Android 自定义控件实现点击波浪效果(九)

必要条件是这个控件需要实现点击事件

package com.rong.activity;

import java.util.ArrayList;

import android.R;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

/**
 * 一个特殊的LinearLayout,任何放入内部的clickable元素都具有波纹效果,当它被点击的时候, 为了性能,尽量不要在内部放入复杂的元素
 * note: long click listener is not supported current for fix compatible bug.
 */
@SuppressWarnings("unused")
public class RectangleWaterWave 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;
	private int mMaxRevealRadius;
	private int mRevealRadiusGap;
	private int mRevealRadius = 0;
	private float mCenterX;
	private float mCenterY;
	private int[] mLocationInScreen = new int[2];

	private boolean mShouldDoAnimation = false;
	private boolean mIsPressed = false;
	private int INVALIDATE_DURATION = 40;

	private View mTouchTarget;
	private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();

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

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

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public RectangleWaterWave(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	private void init() {
		setWillNotDraw(false);
		mPaint.setColor(Color.RED);
	}

	@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) 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);
		int left = location[0] - mLocationInScreen[0];
		int top = location[1] - mLocationInScreen[1];
		int right = left + mTouchTarget.getMeasuredWidth();
		int bottom = top + mTouchTarget.getMeasuredHeight();

		canvas.save();
		Path path = new Path();
//		path.addCircle(180,180, 165, Direction.CCW);
		path.addRoundRect(new RectF(left, top, right, bottom), 7, 7,
				Direction.CCW);
		canvas.clipPath(path);
		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 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);
	}

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

	@SuppressLint("ClickableViewAccessibility")
	@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();
			}
		}
	};

}


你可能感兴趣的:(android,点击波浪效果)