Android——点击水纹效果
16lz
2021-01-26
package com.whr.myapplication;import android.annotation.TargetApi;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.LinearLayout;import java.util.ArrayList;public class MyView 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; // 获取自定义控件MyRevealLayout 在屏幕上的位置 private int[] mLocationInScreen = new int[2]; // 是否执行动画 private boolean mShouldDoAnimation = false; // 是否被按下 private boolean mIsPressed = false; // 重新绘制的时间 单位毫秒 private int INVALIDATE_DURATION = 50; // mTouchTarget指的是用户点击的那个view private View mTouchTarget; // 松手的事件分发线程 private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable(); public MyView(Context context) { super(context); init(); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); init(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setWillNotDraw(false); mPaint.setColor(Color.BLACK); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); this.getLocationOnScreen(mLocationInScreen);//获取在整个屏幕内的绝对坐标 // Log.i("---", "onLayout: "+l+"---"+mLocationInScreen[0]); } /** * 获得最大半径 * @param event * @param view */ private void initParametersForChild(MotionEvent event, View view) { mCenterX = event.getX(); mCenterY = event.getY(); mTargetWidth = view.getMeasuredWidth(); mTargetHeight = view.getMeasuredHeight(); mMinBetweenWidthAndHeight = Math.min(mTargetWidth, mTargetHeight); mMaxBetweenWidthAndHeight = Math.max(mTargetWidth, mTargetHeight); mRevealRadius = 0; mShouldDoAnimation = true; mIsPressed = true; mRevealRadiusGap = mMinBetweenWidthAndHeight / 8; int[] location = new int[2]; view.getLocationOnScreen(location); int left = location[0] - mLocationInScreen[0]; int transformedCenterX = (int) mCenterX - left; mMaxRevealRadius = Math.max(transformedCenterX, mTargetWidth - transformedCenterX); } /** * 绘制水波 */ protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (!mShouldDoAnimation || mTargetWidth <= 0 || mTouchTarget == null) { return; } if (mRevealRadius > mMinBetweenWidthAndHeight / 2) { mRevealRadius += mRevealRadiusGap * 4; } else { 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(mCenterX, mCenterY, mRevealRadius, mPaint); canvas.restore();//save restore 实现了显示 消失 if (mRevealRadius <= mMaxRevealRadius) { postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom); } else if (!mIsPressed) { mShouldDoAnimation = false;//不再花园 postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom); } } @Override public boolean dispatchTouchEvent(MotionEvent 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); mDispatchUpTouchEventRunnable.event = event; postDelayed(mDispatchUpTouchEventRunnable, 40); 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 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() { Log.i("===", "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(); } } };}
更多相关文章
- Android(安卓)instrumentation原理
- Android绘图Canvas、Paint
- android刮刮卡效果
- Android控件显示与隐藏
- Android移动应用知识点总汇①
- Android关于在Canvas类里的绘制线程问题汇总
- Android之RecyclerView巧用payload实现局部刷新
- EditText去掉光标下划线以及点击隐藏hint
- 【Android學習專題】視覺介面篇:Android布局及属性归总(查询用)