RippleEffect(水波纹效果)的实现

您所在的位置:网站首页 水波纹元素分析 RippleEffect(水波纹效果)的实现

RippleEffect(水波纹效果)的实现

2023-12-01 21:42| 来源: 网络整理| 查看: 265

 

Demo 下载:

https://github.com/CodingForAndroid/RippleEffect

学习 谷歌 material design的交互设计、向新技术靠拢~ 

由于谷歌的只有在5.0+才可以有这个效果~ 而我们手头手机大部分还是4.+的、因此自己去实现这个效果、让各种版本的都可以用 无疑是挺好的、

这个Demo 实现了以下几点功能:

①:要实现水波纹效果,首先这个View 必须是可点击的,也就是说clickable :true 才可以触发 比如默认 Button 的Clickable =true,TextView, ImageView =false,但是可以手动设置 true。

②:这个是一个布局、可以包裹 需要实现水波纹效果的 view,任何View 只要是可点击的,都可以包裹进来。

③:可以保证,当手指按下在当前View 上,如果手滑动出了当前View,不会触发该 点击事件, 也就是只有手按下,和手抬起,都是同一个View 才触发 点击事件。

④:这个效果,保证是 水波纹 结束以后,再去响应 View的点击事件 。

⑤:一个布局 包裹这么多View,怎么区分每一个的点击事件呢? 答: 根据 每个View 的id 去响应不同的 事件。

大体就这么多,具体的可以自己尝试,与补充。这个效果参考了  singwhatiwanna 写的、

大体思路 可以去看他的博客、写的很详细、http://blog.csdn.net/singwhatiwanna/article/details/42614953、自己整理 ,为了积累加深一遍。

水波纹效果、就是一圈一圈 向外扩散的圆、实现思路 、就是 以手指触摸的位置为圆心、不断的改变圆的半径、向外画圆、以此达到效果。

而为每一个View 去实现这样一个效果、显然比较费精力,有这样一个布局,可以让其包裹的子View 实现 Ripple 效果,就比较符合我们的需求。

实现思想

首先我们自定义一个layout,这里我们选取LinearLayout,至于原因,文章下面会进行分析。当用户点击一个可点击的元素时,比如button,我们需要得到用户点击的元素的信

息,包含:用户点击了哪个元素、用户点击的那个元素的宽、高、位置信息等。得到了button的信息后,我就可以确定水波纹的范围,然后通过layout进行重绘去绘制水波纹,

这样水波纹效果就实现了,当然,这只是大概步骤,中间还是有一些细节需要处理的。

实现过程

实现过程主要是如下几个问题的解决:

①. 如何得知用户点击了哪个元素

②. 如何取得被点击元素的信息

③. 如何通过layout进行重绘绘制水波纹

④. 如果延迟up事件的分发

如何得知用户点击了哪个元素

这个问题好弄,为了得知用户点击了哪个元素(这个元素一般来说要是可点击的,否则是无意义的),我们要提前拦截所有的点击事件,于是,我们应该重写layout中的

dispatchTouchEvent方法,注意,这里不推荐用onInterceptTouchEvent,因为onInterceptTouchEvent不是一直会被回调的。

然后当用户点击的时候,会有一系列的down、move、up事件,我们要在down的时候来确定事件落在哪个元素上,down的元素就是用户点击的元素,当然为了严谨,我们还

要判断up的时候是否也落在同一个元素上面,因为,系统click事件的判断规则就是:down和up同时落在同一个可点击的元素上。

@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.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, 400); return true; } else if (action == MotionEvent.ACTION_CANCEL) { mIsPressed = false; postInvalidateDelayed(INVALIDATE_DURATION); } return super.dispatchTouchEvent(event); }

通过上述代码,我们可以知道,当down的时候,我们取出点击事件的屏幕坐标,然后去遍历view树找到用户所点击的那个view,代码如下,就是判断事件的坐标是否落在view

的范围内,这个不再多说了,比较好理解。需要注意的是,事件的坐标我们不能用getX和getY,而要用getRawX和getRawY,二者的区别是:前者是相对于被点击view的坐

标,后者是相对于屏幕的坐标,而我们的目标view具体位于layout的哪一层我们无法知道,所以,必须用屏幕的绝对坐标来进行计算。而有了事件的坐标,再根据view在屏幕中

的绝对坐标,只要判断事件的xy是否落在view的上下左右四个角之内,就可以知道事件是否落在view上,从而取出用户所点击的那个view。

private View getTouchTarget(View view, int x, int y) { View target = null; ArrayList 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 = left && x


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3