Android5.0水波纹改进

在参考了任玉刚的水波纹博客之后,在下仿写改进做了另一个demo,效果图如下:



package com.ryg.reveallayout.ui;

import java.util.ArrayList;

import com.zcw.togglebutton.sample.R;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
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;

public class RevealLayout extends LinearLayout implements Runnable {

	private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	/**
	 * 目标View的宽度
	 */
	private int mTargetWidth;
	/**
	 * 目标View的高度
	 */
	private int mTargetHeight;
	/**
	 * 长宽之间取最小距离
	 */
	private int mMinBetweenWidthAndHeight;
	/**
	 * 长宽之间取最大距离
	 */
	private int mMaxBetweenWidthAndHeight;
	/**
	 * 水波纹的最大半径
	 */
	private int mMaxRevealRadius;
	/**
	 * 水波纹的半径间隔
	 */
	private int mRevealRadiusGap;
	/**
	 * 水波纹的初始半径为0
	 */
	private int mRevealRadius = 0;
	/**
	 * 中心点X
	 */
	private float mCenterX;
	/**
	 * 中心点Y
	 */
	private float mCenterY;
	/**
	 * 屏幕中的落点(DOWN,UP)
	 */
	private int[] mLocationInScreen = new int[2];
	/**
	 * 是否显示水波纹动画
	 */
	private boolean mShouldDoAnimation = false;
	/**
	 * 是否被点击
	 */
	private boolean mIsPressed = false;
	/**
	 * 水波纹的延迟时间,越小越快
	 */
	private int INVALIDATE_DURATION = 5;
	/**
	 * 被点击的View
	 */
	private View mTouchTarget;
	/**
	 * 用于DispatchUpTouchEvent绘制的Runnable
	 */
	private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();
	/**
	 * 判断是不是Switch开启
	 */
	private boolean isOpenSwitch;
	/**
	 * 判断是不是Switch关掉
	 */
	private boolean isCloseReveal;

	public boolean isPlayReavel;

	/**
	 * 对外声明一个构造方法使得isOpenSwitch值可以改变
	 */
	public void OpenSwitch(boolean OpenSwitch) {
		isOpenSwitch = OpenSwitch;
	}

	/**
	 * 在父容器中的相对坐标
	 */
	private int mEventX, mEventY;
	private int mRevealLayoutl;
	private int mRevealLayoutt;
	private int mRevealLayoutr;
	private int mRevealLayoutb;

	private int mReavelColor;

	/**
	 * 一个参数的构造函数
	 */
	public RevealLayout(Context context) {
		this(context, null);
		init();
	}

	/**
	 * 2个参数的构造函数
	 */
	public RevealLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		init();
	}

	/**
	 * 3个参数的构造函数
	 */
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public RevealLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.RevealLayout, defStyleAttr, 0);
		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			case R.styleable.RevealLayout_ReavelColor:
				mReavelColor = a.getColor(attr,getResources().getColor(R.color.reveal_color));
				break;
			}
		}
		a.recycle();
		/**
		 * 视图的初始化
		 */
		init();
	}

	/**
	 * 视图的初始化
	 */
	private void init() {
		/**
		 * 为了是draw方法或者类似的方法执行有效
		 */
		setWillNotDraw(false);
		/**
		 * 画笔颜色的初始化
		 */
		mPaint.setColor(mReavelColor);
	}

	/**
	 * 布局的初始化
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		/**
		 * 获取屏幕中的落点
		 */
		this.getLocationOnScreen(mLocationInScreen);
	}

	/**
	 * 测量子View的一些参数,如触摸点和宽高等数据
	 */
	private void initParametersForChild(MotionEvent event, View view) {
		/**
		 * 将触摸点的设置为圆心坐标mCenterX,mCenterY
		 */
		mCenterX = event.getX();
		mCenterY = event.getY();
		/**
		 * 测量子View的高度和宽度
		 */
		mTargetWidth = view.getMeasuredWidth();
		mTargetHeight = view.getMeasuredHeight();
		/**
		 * 长宽之间取最小距离
		 */
		mMinBetweenWidthAndHeight = Math.min(mTargetWidth, mTargetHeight);
		/**
		 * 长宽之间取最大距离
		 */
		mMaxBetweenWidthAndHeight = Math.max(mTargetWidth, mTargetHeight);
		/**
		 * 水波纹的半径初始为0
		 */
		if (mRevealRadius <= 0) {
			mRevealRadius = 0;
		} else {
			mRevealRadius = Math.max(mRevealLayoutr, mRevealLayoutb);
			isCloseReveal = true;
		}
		isPlayReavel = true;
		/**
		 * 显示水波纹
		 */
		mShouldDoAnimation = true;
		/**
		 * 按下标志位设置为true
		 */
		mIsPressed = true;
		/**
		 * 水波纹之间间隔为mMinBetweenWidthAndHeight / 8
		 */

		mRevealRadiusGap = mMinBetweenWidthAndHeight / 8;
		/**
		 * 触摸点的坐标x,y放在location数组中
		 */
		int[] location = new int[2];
		/**
		 * 获取子View中的落点
		 */
		view.getLocationOnScreen(location);
		/**
		 * 子View中心location【0】-落点的x坐标就是落点距离子view的左边边距 mLocationInScreen[0]=0
		 */
		int left = location[0] - mLocationInScreen[0];
		/**
		 * 触摸点距离左边View的边距
		 */
		int transformedCenterX = (int) mCenterX - left;
		/**
		 * 水波纹的最大半径
		 */
		mMaxRevealRadius = Math.max(transformedCenterX, mTargetWidth
				- transformedCenterX);

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mRevealLayoutr = MeasureSpec.getSize(widthMeasureSpec);
		mRevealLayoutb = MeasureSpec.getSize(heightMeasureSpec);
	}

	@Override
	public void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (!mShouldDoAnimation || mTargetWidth <= 0 || mTouchTarget == null) {
			return;
		}
		if (isOpenSwitch) {
			if (mRevealRadius > mMinBetweenWidthAndHeight / 2) {
				mRevealRadius += mRevealRadiusGap * 8;
			} else {
				mRevealRadius += mRevealRadiusGap * 8;
			}
		}

		if (isCloseReveal) {
			if (mRevealRadius > mMinBetweenWidthAndHeight / 2) {
				mRevealRadius -= mRevealRadiusGap * 8;
			} else {
				mRevealRadius -= mRevealRadiusGap * 8;
			}
		}
		this.getLocationOnScreen(mLocationInScreen);
		int[] location = new int[2];
		mTouchTarget.getLocationOnScreen(location);
		int left = mRevealLayoutl;
		int top = mRevealLayoutt;
		int right = mRevealLayoutr;
		int bottom = mRevealLayoutb;
		Log.e("TAG", "left:" + left + "top:" + top + "right:" + right
				+ "bottom" + bottom + "mRevealRadius" + mRevealRadius);
		canvas.save();
		canvas.clipRect(left, top, right, bottom);
		canvas.drawCircle(mCenterX, mCenterY, mRevealRadius, mPaint);
		canvas.restore();
		// 水波纹半径设置最大为right,bottom最大值
		if (mRevealRadius >= Math.max(right, bottom)*2) {
			isCloseReveal = true;
			isPlayReavel = false;
			return;
		}
		// 波纹减小到0退出
		if (mRevealRadius < 0) {
			isCloseReveal = false;
			isPlayReavel = false;
			return;
		}
		if (mRevealRadius <= Math.max(right, bottom)) {
			postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
		} else if (!mIsPressed) {
			if (!isOpenSwitch) {
				mShouldDoAnimation = false;
			}
			// 重新触发dispatchDraw事件会直接退出
			postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
		}

	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		/**
		 * 触摸点的x,y坐标
		 */
		int x = (int) event.getRawX();
		int y = (int) event.getRawY();

		mEventX = (int) event.getX();
		mEventY = (int) event.getY();

		Log.e("TAG", "x:" + x + "Y:" + y + "mEvent" + mEventX + "mEventY"
				+ mEventY);
		/**
		 * 触摸行为是down还是up还是move等其他
		 */
		int action = event.getAction();

		/**
		 * 是Down的话
		 */
		if (action == MotionEvent.ACTION_DOWN) {
			// 根据坐标获取到view,可点击并且落点在可点击View内部返回值才不为空,其他都为空
			View touchTarget = getTouchTarget(this, x, y);
			if (touchTarget != null && touchTarget.isClickable()
					&& touchTarget.isEnabled()) {
				// 将点击子View传给mTouchTarget
				mTouchTarget = touchTarget;
				// 初始化子View的参数和水波纹半径
				initParametersForChild(event, touchTarget);
				// 触发dispatchDraw
				postInvalidateDelayed(INVALIDATE_DURATION);
			}
		} else if (action == MotionEvent.ACTION_UP) {
			// 抬起时候将点击标志位设置为false
			mIsPressed = false;
			// 触发dispatchDraw
			postInvalidateDelayed(INVALIDATE_DURATION);
			mDispatchUpTouchEventRunnable.event = event;
			// 后面的参数会影响点是绘制播放时间,设置适量大一点可以实现播放完波纹在执行点击事件
			postDelayed(mDispatchUpTouchEventRunnable, 0);
			return true;
		} else if (action == MotionEvent.ACTION_CANCEL) {
			mIsPressed = false;
			// 触发dispatchDraw
			postInvalidateDelayed(INVALIDATE_DURATION);
		}
		return super.dispatchTouchEvent(event);
	}

	/**
	 * 根据x,y坐标来获取触摸的子View
	 */
	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();
		/**
		 * 判断触摸点是不是在子View的上下左右四个点围成矩形内部
		 */
		if (view.isClickable() && y >= top && y <= bottom && x >= left
				&& x <= right) {
			return true;
		}
		return false;
	}

	@Override
	public boolean performClick() {
		postDelayed(this, 400);
		return true;
	}

	public void run() {
		/**
		 * 模拟点击事件
		 */
		super.performClick();
	}

	private class DispatchUpTouchEventRunnable implements Runnable {
		public MotionEvent event;

		public void run() {
			if (mTouchTarget == null || !mTouchTarget.isEnabled()) {
				return;
			}

			if (isTouchPointInView(mTouchTarget, (int) event.getRawX(),
					(int) event.getRawY())) {
				// 目标的点击时间延迟400ms保证动画执行完之后才触发点击事件,模拟点击事件
				mTouchTarget.performClick();
			}
		}
	};

}



其实都没有什么可以说的,注释都一行行解释的很清楚了,感谢任玉刚大神的demon让我有机会改进写出自己的demon
这是任大神的博客水波纹地址:http://blog.csdn.net/singwhatiwanna/article/details/42614953

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值