Android 點選單個按鈕或者其他的View,在view上出現水波紋效果,然後執行點選事件。
1.自定義一個佈局,得到點選的view,在view上繪畫水波紋,水波紋的圓心是view的中點,半徑為寬和高一半的最小值。
package com.example.waterview;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
public class WaterLinearLayout extends LinearLayout implements Runnable{
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 被點選的控制元件的寬高
private int mTargetWidth;
private int mTargetHeight;
// 在被選中的控制元件長寬中的最大值和最小值
// private int mMinBetweenWidthAndHeight;
// private int mMaxBetweenWidthAndHeight;
// mMaxRadius為繪製的水波紋圓圈最大的半徑
private int mMaxRevealRadius;
// mRevealRadiusGap為每次重新繪製半徑增加的值
private int mRevealRadiusGap;
// mRevealRadius為初始的數值
private int mRevealRadius = 0;
// 使用者點選處的座標
// private float mCenterX;
// private float mCenterY;
// 獲取自定義控制元件WaterLinearLayout 在螢幕上的位置
private int[] mLocationInScreen = new int[2];
// 是否執行動畫
private boolean mShouldDoAnimation = false;
// 是否被按下
// private boolean mIsPressed = false;
private MotionEvent mchildEvent;
// 重新繪製的時間 單位毫秒
private int INVALIDATE_DURATION = 80;
// mTouchTarget指的是使用者點選的那個view
private View mTouchTarget;
// 鬆手的事件分發執行緒
private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();
public WaterLinearLayout(Context context)
{
super(context);
init();
}
public WaterLinearLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public WaterLinearLayout(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
private void init()
{
setWillNotDraw(false);
mPaint.setColor(getResources().getColor(R.color.waterline_color));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
this.getLocationOnScreen(mLocationInScreen);
}
private void initParametersForChild(MotionEvent event, View view)
{
mTargetWidth = view.getMeasuredWidth();
mTargetHeight = view.getMeasuredHeight();
// mMinBetweenWidthAndHeight = Math.min(mTargetWidth, mTargetHeight);
mRevealRadius = 0;
mShouldDoAnimation = true;
// mIsPressed = true;
mMaxRevealRadius = Math.min(mTargetHeight/2, mTargetWidth/2);
mRevealRadiusGap = mMaxRevealRadius / 32;
}
/**
* 繪製水波
*/
protected void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
if (!mShouldDoAnimation || mTargetWidth <= 0 || mTouchTarget == null)
{
return;
}
mRevealRadius += mRevealRadiusGap;
this.getLocationOnScreen(mLocationInScreen);
int[] location = new int[2];
mTouchTarget.getLocationOnScreen(location);
// 獲得要繪製View的left, top, right, bottom值
int left = location[0] - mLocationInScreen[0];
int top = location[1] - mLocationInScreen[1];
int right = left + mTouchTarget.getMeasuredWidth();
int bottom = top + mTouchTarget.getMeasuredHeight();
canvas.save();
canvas.clipRect(left, top, right, bottom);
canvas.drawCircle(mTargetWidth/2+left, top+mTargetHeight/2, mRevealRadius, mPaint);
canvas.restore();
if (mRevealRadius <= mMaxRevealRadius)
{
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
} else{
mShouldDoAnimation = false;
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
mDispatchUpTouchEventRunnable.event = mchildEvent;
postDelayed(mDispatchUpTouchEventRunnable, 50);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
mchildEvent = event;
// 獲得相對於螢幕的座標
int x = (int) event.getRawX();
int y = (int) event.getRawY();
// 獲得動作
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN)
{
View touchTarget = getTouchTarget(this, x, y);
if (touchTarget != null && touchTarget.isClickable() && touchTarget.isEnabled())
{
mTouchTarget = touchTarget;
initParametersForChild(event, touchTarget);
// 重新整理介面,延遲執行時間
postInvalidateDelayed(INVALIDATE_DURATION);
}
} else if (action == MotionEvent.ACTION_UP)
{
// mIsPressed = false;
postInvalidateDelayed(INVALIDATE_DURATION);
// Log.d("sdd", "mIsFinish = "+mIsFinish);
// if (mIsFinish) {
//mDispatchUpTouchEventRunnable.event = event;
//postDelayed(mDispatchUpTouchEventRunnable, 50);
//}
return true;
} else if (action == MotionEvent.ACTION_CANCEL)
{
// mIsPressed = false;
postInvalidateDelayed(INVALIDATE_DURATION);
}
return super.dispatchTouchEvent(event);
}
/**
* 遍歷view樹找到使用者所點選的那個view
*
* @param view
* @param x
* @param y
* @return
*/
private View getTouchTarget(View view, int x, int y)
{
View target = null;
ArrayList<View> TouchableViews = view.getTouchables();
for (View child : TouchableViews)
{
if (isTouchPointInView(child, x, y))
{
target = child;
break;
}
}
return target;
}
/**
* 判斷事件的xy是否落在view的上下左右四個角之內
*
* @param view
* @param x
* @param y
* @return
*/
private boolean isTouchPointInView(View view, int x, int y)
{
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
if (view.isClickable() && y >= top && y <= bottom && x >= left && x <= right)
{
return true;
}
return false;
}
// 使用程式碼主動去呼叫控制元件的點選事件(模擬人手去觸控控制元件)
@Override
public boolean performClick()
{
postDelayed(this, 400);
return true;
}
@Override
public void run()
{
super.performClick();
}
private class DispatchUpTouchEventRunnable implements Runnable
{
public MotionEvent event;
@Override
public void run()
{
if (mTouchTarget == null || !mTouchTarget.isEnabled())
{
return;
}
if (isTouchPointInView(mTouchTarget, (int) event.getRawX(), (int) event.getRawY()))
{
// 使用程式碼主動去呼叫控制元件的點選事件(模擬人手去觸控控制元件)
mTouchTarget.performClick();
}
}
};
}
2.xml佈局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.waterview.WaterLinearLayout
android:layout_width="400dp"
android:layout_height="500dp"
android:padding="50dp"
android:orientation="vertical" >
<Button
android:onClick="close"
android:layout_width="100dp"
android:layout_height="100dp"
android:text="關閉"
android:background="@drawable/close_selector"/>
</com.example.waterview.WaterLinearLayout>
</RelativeLayout>
3.按鈕的點選效果,圖片自行定義,close_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="@drawable/image02" android:state_pressed="true"/>
<item android:drawable="@drawable/gougou2" android:state_focused="false" android:state_pressed="false"/>
</selector>
4.Activity主檔案
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void close(View view){
//Toast.makeText(this, "關閉", 0).show();
Log.d("MainActivity", "close");
}
}