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();            }        }    };}

更多相关文章

  1. Android(安卓)instrumentation原理
  2. Android绘图Canvas、Paint
  3. android刮刮卡效果
  4. Android控件显示与隐藏
  5. Android移动应用知识点总汇①
  6. Android关于在Canvas类里的绘制线程问题汇总
  7. Android之RecyclerView巧用payload实现局部刷新
  8. EditText去掉光标下划线以及点击隐藏hint
  9. 【Android學習專題】視覺介面篇:Android布局及属性归总(查询用)

随机推荐

  1. 【问题汇总】透明Activity引起的问题
  2. Android联系人数据库全解析-2.0以上
  3. Android模拟器——QEMU
  4. 安卓布局被软键盘顶上去的解决方案
  5. Android四种启动模式及其注意事项
  6. android切换到后台,返回后图片纹理丢失
  7. android am命令
  8. Android(安卓)O - 为什么要引入HIDL
  9. Android(安卓)应用程序签名
  10. Android(安卓)Day03-SQLite数据库操作及L