自定義按鈕實現水波點擊效果

1運行效果

這裏寫圖片描述

2自定義佈局

public class RevealLayout extends LinearLayout implements Runnable {

    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private int[] mLocationInScreen = new int[2];

    private float mCenterX;
    private float mCenterY;

    private int mTargetWidth;
    private int mTargetHeight;

    private int mMaxBetweenWidthAndHeight;
    private int mMinBetweenWidthAndHeight;

    private int mMaxRevealRadius;

    private int mRevealRadiusGap;

    private int mRevealRadius = 0;

    private boolean mShouldDoAnimation = false;
    private boolean mIsPressed = false;

    private View mTouchTarget;

    private int INVALIDATE_DURATION = 40;

    private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();


    public RevealLayout(Context context) {
        super(context);
        init();
    }

    public RevealLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RevealLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        setWillNotDraw(false);
        mPaint.setColor(getResources().getColor(#1b000000));
    }

    @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){
        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)mCenterY - left;
        mMaxRevealRadius = Math.max(transformedCenterX,mTargetWidth - transformedCenterX);
    }

    @Override
    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);
        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();

        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 ev) {
        int x = (int) ev.getRawX();
        int y = (int) ev.getRawY();
        int action = ev.getAction();
        if(action == MotionEvent.ACTION_DOWN){
            View touchTarget = getTouchTarget(this,x,y);
            if(touchTarget != null && touchTarget.isClickable() && touchTarget.isEnabled()){
                mTouchTarget = touchTarget;
                initParametersForChild(ev,touchTarget);
                postInvalidateDelayed(INVALIDATE_DURATION);
            }
        }else if (action == MotionEvent.ACTION_UP){
            mIsPressed = false;
            postInvalidateDelayed(INVALIDATE_DURATION);
            mDispatchUpTouchEventRunnable.event = ev;
            postDelayed(mDispatchUpTouchEventRunnable,40);
            return true;
        }else if (action == MotionEvent.ACTION_CANCEL){
            mIsPressed = false;
            postInvalidateDelayed(INVALIDATE_DURATION);
        }
        return super.dispatchTouchEvent(ev);
    }

    private View getTouchTarget(View view,int x, int y){
        View target = null;
        ArrayList<View> TouchableView = view.getTouchables();
        for (View child : TouchableView){
            if(isTouchPointInView(child,x,y)){
                target = child;
                break;
            }
        }
        return target;
    }

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

3佈局activity_main

?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:background="#ffffff"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.my.waterbatton.ui.RevealLayout
        android:id="@+id/layout1"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/btn1"
            style="@style/AppTheme.Button.Green"
            android:enabled="true"
            android:text="Button"
            android:layout_width="match_parent"
             />
    </com.my.waterbatton.ui.RevealLayout>
    <com.my.waterbatton.ui.RevealLayout
        android:id="@+id/layout2"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:orientation="vertical"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/button1"
            style="@style/AppTheme.Button.Green"
            android:layout_width="200dp"
            android:enabled="true"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            style="@style/AppTheme.Button.Green"
            android:layout_margin="10dp"
            android:enabled="true"
            android:text="Button" />

        <Button
            android:id="@+id/button3"
            style="@style/AppTheme.Button.Highlight"
            android:layout_margin="10dp"
            android:enabled="true"
            android:text="Button" />

        <Button
            android:id="@+id/button4"
            style="@style/AppTheme.Button.Highlight"
            android:layout_height="100dp"
            android:layout_margin="10dp"
            android:enabled="true"
            android:text="Button" />

    </com.my.waterbatton.ui.RevealLayout>
</LinearLayout>

4 styles定義重複代碼

 <style name="AppTheme.Button">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">44dp</item>
        <item name="android:textSize">18dp</item>
    </style>

    <style name="AppTheme.Button.Green">
        <item name="android:background">#0ac39e</item>
        <item name="android:textColor">#ffffff</item>
    </style>

    <style name="AppTheme.Button.Highlight">
        <item name="android:background">#4185f2</item>
        <item name="android:textColor">#ffffff</item>
    </style>

源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章