Android 5.0水波纹效果
2015-07-29 17:32
183 查看
前言
上篇博客已经是很久以前了,这段时间的确是忙了很多,技术相关的也做的少了。近期一个项目中,需要在4.4上实现一些5.0上的特效,例如Button之类的控件点击时的水波纹效果。在blog里找到了任教主的一篇博文,受到了启发,将他的Demo改动了一些就实现了。具体在应用到自己项目中时遇到了些需求变化和其他问题,这里就相当于做一个记录。
效果演示
AS还是不怎么会用,gif的图就没有了,这里给个静态的
这里说明一下,这个截图是一个拨号盘,在拨号的时候会有水波纹效果。
从效果图中可以看出与其他水波纹Demo的差异之处在于这个水波纹可以突破控件自身的大小。
思路
重载dispatchTouchEvent获取相应的坐标以及绘制对象,
重载dispatchDraw,根据点击事件来绘制一个逐渐变大的Circle。
代码及说明
Java代码
我这继承的是一个TabLayout,当然也可以继承其他的Layout实现相同效果。
由于是要做一个扩散出来的水波纹,这里的circle就的圆心就取的是死的,没有根据event来获取,需求不一致就需要重新计算canvas.drawCircle(left+mTargetWidth/2, top+mTargetHeight/2, mRevealRadius, mPaint);和postInvalidateDelayed(INVALIDATE_DURATION, left, top-mMaxRevealRadius, right, bottom+mMaxRevealRadius);
最后有几个需要提醒的地方是,dispatchTouchEvent中最好只return super.dispatchTouchEvent(event);
否则可能会出现长按事件混淆的问题。
上篇博客已经是很久以前了,这段时间的确是忙了很多,技术相关的也做的少了。近期一个项目中,需要在4.4上实现一些5.0上的特效,例如Button之类的控件点击时的水波纹效果。在blog里找到了任教主的一篇博文,受到了启发,将他的Demo改动了一些就实现了。具体在应用到自己项目中时遇到了些需求变化和其他问题,这里就相当于做一个记录。
效果演示
AS还是不怎么会用,gif的图就没有了,这里给个静态的
这里说明一下,这个截图是一个拨号盘,在拨号的时候会有水波纹效果。
[code]对比Demo中的效果 ![这里写图片描述](http://img.blog.csdn.net/20150729171157159)
从效果图中可以看出与其他水波纹Demo的差异之处在于这个水波纹可以突破控件自身的大小。
思路
重载dispatchTouchEvent获取相应的坐标以及绘制对象,
重载dispatchDraw,根据点击事件来绘制一个逐渐变大的Circle。
代码及说明
Java代码
[code] public class CustomTableLayout extends TableLayout{ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mBgPaint = 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 int[] mLocationInScreen = new int[2]; /**是否绘制水波纹*/ private boolean mShouldDoAnimation = false; /**点击状态*/ private boolean mIsPressed = false; /**绘制间隔*/ private int INVALIDATE_DURATION = 40; /**点击的View*/ private View mTouchTarget; public CustomTableLayout(Context context) { super(context); init(); } public CustomTableLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setWillNotDraw(false); mPaint.setColor(getResources().getColor(R.color.reveal_color_2)); mBgPaint.setColor(getResources().getColor(R.color.reveal_color_2)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); this.getLocationOnScreen(mLocationInScreen); } /** * @Title: initParametersForChildNew * @Description: 初始化各个参数 * @param: @param view * @return: void * @throws */ private void initParametersForChildNew(View view){ 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); //突破控件大小的关键之一 mMaxRevealRadius = mMaxBetweenWidthAndHeight/4 +2*mRevealRadiusGap; } /** * @Title: getTouchTarget * @Description: 获取点击的View * @param: @param view * @param: @param x * @param: @param y * @param: @return * @return: View * @throws */ 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; } /** * @Title: isTouchPointInView * @Description: 判断point是否是处于View中 * @param: @param view * @param: @param x * @param: @param y * @param: @return * @return: boolean * @throws */ 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 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; initParametersForChildNew(touchTarget); postInvalidateDelayed(INVALIDATE_DURATION); } } else if (action == MotionEvent.ACTION_UP) { mIsPressed = false; postInvalidateDelayed(INVALIDATE_DURATION*2); } else if (action == MotionEvent.ACTION_CANCEL) { mIsPressed = false; postInvalidateDelayed(INVALIDATE_DURATION); } return super.dispatchTouchEvent(event); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (!mShouldDoAnimation || mTargetWidth <= 0 || mTouchTarget == null) { return; } if (mRevealRadius > mMaxRevealRadius) { } 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-mRevealRadius, right, bottom+mRevealRadius); canvas.drawCircle(left+mTargetWidth/2, top+mTargetHeight/2, mMaxRevealRadius, mBgPaint); canvas.drawCircle(left+mTargetWidth/2, top+mTargetHeight/2, mRevealRadius, mPaint); canvas.restore(); if (mRevealRadius <= mMaxRevealRadius) { postInvalidateDelayed(INVALIDATE_DURATION, left, top-mMaxRevealRadius, right, bottom+mMaxRevealRadius); } else if (!mIsPressed) { mShouldDoAnimation = false; postInvalidateDelayed(INVALIDATE_DURATION, left, top-mMaxRevealRadius, right, bottom+mMaxRevealRadius); } } }
我这继承的是一个TabLayout,当然也可以继承其他的Layout实现相同效果。
由于是要做一个扩散出来的水波纹,这里的circle就的圆心就取的是死的,没有根据event来获取,需求不一致就需要重新计算canvas.drawCircle(left+mTargetWidth/2, top+mTargetHeight/2, mRevealRadius, mPaint);和postInvalidateDelayed(INVALIDATE_DURATION, left, top-mMaxRevealRadius, right, bottom+mMaxRevealRadius);
最后有几个需要提醒的地方是,dispatchTouchEvent中最好只return super.dispatchTouchEvent(event);
否则可能会出现长按事件混淆的问题。
相关文章推荐
- Android日常小问题收集库
- 兼容Android的水波纹效果
- Android Studio 模板(Template)定制
- 【Android】神奇的android:clipChildren属性
- android反编译
- Android MVP开发。
- Android调试命令总结
- Android 单元测试——AndroidTestCase
- android 时间大小比较
- Android指针管理:RefBase,SP,WP
- android之布局优化
- Android FindMyPhone功能模块的实现
- 八款常见的Android游戏引擎
- Android中关于Adapter的使用(中)SimpleAdapter
- Android中关于Adapter的使用(上)ArrayAdapter
- 拖拽RecyclerView
- Android Wifi简单管理与操作
- Android中关于Adapter的使用(下)BaseAdapter
- android INSTALL_FAILED_VERSION_DOWNGRADE 解决之道
- The connection to adb is down, and a severe error has occured解决