天天看點

Android 實作單擊View,中間出現水波紋效果,在執行點選事件。

1.自定義布局

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;    

    // mMaxRadius為繪制的水波紋圓圈最大的半徑    

    private int mMaxRevealRadius;    

    // mRevealRadiusGap為每次重新繪制半徑增加的值    

    private int mRevealRadiusGap;    

    // mRevealRadius為初始的數值    

    private int mRevealRadius = 0;    

    // 擷取自定義控件WaterLinearLayout 在螢幕上的位置    

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

    // 是否執行動畫    

    private boolean mShouldDoAnimation = 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();       

        mRevealRadius = 0;    

        mShouldDoAnimation = 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)    

        {     

            postInvalidateDelayed(INVALIDATE_DURATION); 

            return true;    

        } else if (action == MotionEvent.ACTION_CANCEL)    

        {    

            postInvalidateDelayed(INVALIDATE_DURATION);    

        }    

        return super.dispatchTouchEvent(event);    

    }    

    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;    

    }    

    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.主函數程式

package com.example.waterview;

import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.widget.Toast;

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");

}

}