Android源码解析--Material Design之水波纹点击效果RippleEffect使用

简介: 版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48505041 Android5.0已经出了好久了,但是目前市场上的App好像没有多少用5.0上面的一些效果,依旧延续着之前的控件使用,但是既然新的东西已经出来了,就必定会淘汰旧的不好的,所以我们要与时俱进。
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48505041

Android5.0已经出了好久了,但是目前市场上的App好像没有多少用5.0上面的一些效果,依旧延续着之前的控件使用,但是既然新的东西已经出来了,就必定会淘汰旧的不好的,所以我们要与时俱进。其中Material Design真的很不错,其中有好多酷炫的动画,Android5.0的SwipeRefreshLayout会取代之前的PullToRefreshListView、RecyclerView,CardView也会取代ListView、MaterialEdittext也会取代Edittex以及一些FloatButton等等,以后会逐一介绍的。今天我们看一下RippleEffect水波纹点击效果,先上图:


大家可以看到按钮或者布局点击的时候会有水波涟漪的效果,很不错,用到你的app上一定会很高大上的。

下面我们分析一下源码,然后再看怎么使用,因为我觉得如果你光会用但是不了解怎么实现的你最多也就算个码农,所以我们要尝试着读懂源码,然后再尝试着自己定义view

首先在init()方法中初始化一些组件和styles,并设置相应的属性包括设置画布的抗锯齿标志、画图的实心空心、透明度颜色的设置。

[java]  view plain copy
  1. <span style="font-size:14px;"><span style="white-space: pre;">  </span>paint = new Paint();  
  2.         paint.setAntiAlias(true);   //设置画布抗锯齿标志  
  3.         paint.setStyle(Paint.Style.FILL);   //设置画图实心  
  4.         paint.setColor(rippleColor);    //设置画图颜色  
  5.         paint.setAlpha(rippleAlpha);    //设置透明度  
  6.         this.setWillNotDraw(false);     //设置将不绘画</span>  
然后创建手势,因为我们的点击有可能为长点击,我们用手势来做一些操作

[java]  view plain copy
  1. <span style="font-size:14px;"><span style="white-space:pre">    </span>/** 
  2.          * 创建新的手势 
  3.          */  
  4.         gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {  
  5.             @Override  
  6.             public void onLongPress(MotionEvent event) {  
  7.                 super.onLongPress(event);  
  8.                 animateRipple(event);   //创建动画  
  9.                 sendClickEvent(true);   //发送长点击事件  
  10.             }  
  11.   
  12.             @Override  
  13.             public boolean onSingleTapConfirmed(MotionEvent e) {  
  14.                 return true;  
  15.             }  
  16.   
  17.             @Override  
  18.             public boolean onSingleTapUp(MotionEvent e) {  
  19.                 return true;  
  20.             }  
  21.         });  
  22.   
  23.         this.setDrawingCacheEnabled(true);  //更新cache,提高绘图速度  
  24.         this.setClickable(true);</span>  
接下来重写OnDraw()方法

[java]  view plain copy
  1. <span style="font-size:14px;">@Override  
  2.     public void draw(Canvas canvas) {  
  3.         super.draw(canvas);  
  4.         if (animationRunning) {  
  5.             if (rippleDuration <= timer * frameRate) {  
  6.                 animationRunning = false;  
  7.                 timer = 0;  
  8.                 durationEmpty = -1;  
  9.                 timerEmpty = 0;  
  10.                 canvas.restore();  
  11.                 invalidate();  
  12.                 if (onCompletionListener != null) onCompletionListener.onComplete(this);  
  13.                 return;  
  14.             } else  
  15.                 canvasHandler.postDelayed(runnable, frameRate);  
  16.   
  17.             if (timer == 0)  
  18.                 canvas.save();  
  19.   
  20.   
  21.             canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);   //画圆的半径  
  22.   
  23.             paint.setColor(Color.parseColor("#ffff4444"));  //设置颜色  
  24.   
  25.             if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {  
  26.                 if (durationEmpty == -1)  
  27.                     durationEmpty = rippleDuration - timer * frameRate;  
  28.   
  29.                 timerEmpty++;  
  30.                 //创建圆的bitmap  
  31.                 final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));  
  32.                 canvas.drawBitmap(tmpBitmap, 00, paint);  
  33.                 tmpBitmap.recycle();  
  34.             }  
  35.   
  36.             paint.setColor(rippleColor);  
  37.   
  38.             if (rippleType == 1) {  
  39.                 if ((((float) timer * frameRate) / rippleDuration) > 2f)  
  40.                     paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));  
  41.                 else  
  42.                     paint.setAlpha(rippleAlpha);  
  43.             }  
  44.             else  
  45.                 paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));  
  46.   
  47.             timer++;  
  48.         }  
  49.     }</span>  
这里面包括我们设置圆的颜色、半径大小,透明度(透明度是根据距离的增长而越来越透明的)

最重要的核心部分也就是创建动画了:

[java]  view plain copy
  1. <span style="font-size:18px;">     </span><span style="font-size:14px;">/** 
  2.      * Create Ripple animation centered at x, y 
  3.      * 
  4.      * @param x Horizontal position of the ripple center 
  5.      * @param y Vertical position of the ripple center 
  6.      */  
  7.     private void createAnimation(final float x, final float y) {  
  8.         if (this.isEnabled() && !animationRunning) {  
  9.             if (hasToZoom)  
  10.                 this.startAnimation(scaleAnimation);  
  11.   
  12.             radiusMax = Math.max(WIDTH, HEIGHT);  
  13.   
  14.             if (rippleType != 2)  
  15.                 radiusMax /= 1;  
  16.   
  17.             radiusMax -= ripplePadding;  
  18.   
  19.             if (isCentered || rippleType == 1) {  
  20.                 this.x = getMeasuredWidth() ;  
  21.                 this.y = getMeasuredHeight() ;  
  22.             } else {  
  23.                 this.x = x;  
  24.                 this.y = y;  
  25.             }  
  26.   
  27.             animationRunning = true;  
  28.   
  29.             if (rippleType == 1 && originBitmap == null)  
  30.                 originBitmap = getDrawingCache(true);  
  31.   
  32.             invalidate();  
  33.         }  
  34.     }</span>  
我们可以在这里面设置圆的最大半径,最大半径越大,我们得到的水波涟漪效果越快,越小,得到的水波涟漪效果越慢,也就是radiusMax /=1,这句代码。

那我们的动画怎么设置呢?当然用ScaleAnimation动画了

[java]  view plain copy
  1. <span style="font-size:14px;">@Override  
  2.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  3.         super.onSizeChanged(w, h, oldw, oldh);  
  4.         WIDTH = w;  
  5.         HEIGHT = h;  
  6.   
  7.         scaleAnimation = new ScaleAnimation(2.0f, zoomScale, 2.0f, zoomScale, w / 2, h / 2);  
  8.         scaleAnimation.setDuration(zoomDuration);  
  9.         scaleAnimation.setRepeatMode(Animation.REVERSE);  
  10.         scaleAnimation.setRepeatCount(1);  
  11.     }</span>  
它的参数如下:

ScaleAnimation(float fromX, float toX, float fromY, float toY,int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)   

参数说明:   

float fromX 动画起始时 X坐标上的伸缩尺寸   

float toX 动画结束时 X坐标上的伸缩尺寸   

float fromY 动画起始时Y坐标上的伸缩尺寸   

float toY 动画结束时Y坐标上的伸缩尺寸   

int pivotXType 动画在X轴相对于物件位置类型   

float pivotXValue 动画相对于物件的X坐标的开始位置   

int pivotYType 动画在Y轴相对于物件位置类型   

float pivotYValue 动画相对于物件的Y坐标的开始位置  


好了,这样差不多就完成了我们的水波涟漪效果了。。。。

看一下怎么用吧?

如果你的开发IDE是Android Studio那么我们可以把github上的库集成到我们的项目中,

[java]  view plain copy
  1. <span style="font-size:14px;">dependencies {    
  2.     compile 'com.github.traex.rippleeffect:library:1.2.3'    
  3. } </span>  
在我们的布局中引用RippleEffect就OK了

[java]  view plain copy
  1. <span style="font-size:14px;"><com.Hankkin.library.RippleView    
  2.   android:id="@+id/more"    
  3.   android:layout_width="?android:actionBarSize"    
  4.   android:layout_height="?android:actionBarSize"    
  5.   android:layout_toLeftOf="@+id/more2"    
  6.   android:layout_margin="5dp"    
  7.   ripple:rv_centered="true">    
  8.      
  9.   <ImageView    
  10.     android:layout_width="?android:actionBarSize"    
  11.     android:layout_height="?android:actionBarSize"    
  12.     android:src="@android:drawable/ic_menu_edit"    
  13.     android:layout_centerInParent="true"    
  14.     android:padding="10dp"    
  15.     android:background="@android:color/holo_blue_dark"/>    
  16.      
  17. </com.Hankkin.library.RippleView>  </span>  
当然你也可以把库中的RippleView直接拷到我们的项目里面,还可以该里面的动画快慢速度等,注意也要把库里面的styles,attrs拷进来,放到自己的项目里面,就可以自己改一些配置了。

——————————————————————————————————————————————————————————————————————————————————————————————————————

下面再和大家说一下比较重要的一点吧,这个网上的demo都没有说,是我自己用的时候发现的

也就是我们的点击事件,这时候如果你还用普通的OnClickListener()是不行的,因为动画还没有结束,就直接startIntent()跳转界面了,如果你的界面没有finish()掉的话,返回的时候动画会继续执行完。

那么怎么破呢?

我们就需要给我们的RippleView设置监听事件而不是我们的控件设置监听事件了,因为我们的RippleView中有这样一个接口:

[java]  view plain copy
  1. <span style="font-size:14px;">public interface OnRippleCompleteListener {    
  2.         void onComplete(RippleView rippleView);    
  3.     } </span>  
也就是动画完成的事件
[java]  view plain copy
  1. <span style="font-size:14px;">RippleView view = (RippleView) findViewById(R.id.reView);    
  2.         view.setOnRippleCompleteListener(new RippleView.OnRippleCompleteListener() {    
  3.             @Override    
  4.             public void onComplete(RippleView rippleView) {    
  5.                 Intent intent = new Intent(getApplicationContext(),HelloActivity.class);    
  6.                 startActivity(intent);    
  7.             }    
  8.         });  </span>  
这样我们就实现了动画完成之后才来实现界面跳转了

小伙伴们,快试一下吧。

当然我们的ListView的item点击也可以实现这样的效果,因为我们的RippleView中是支持Listview点击的

[java]  view plain copy
  1. /**  
  2.      * Send a click event if parent view is a Listview instance  
  3.      * 若为Listview发送点击事件  
  4.      * @param isLongClick Is the event a long click ?  
  5.      */    
  6.     private void sendClickEvent(final Boolean isLongClick) {    
  7.         if (getParent() instanceof AdapterView) {    
  8.             final AdapterView adapterView = (AdapterView) getParent();    
  9.             final int position = adapterView.getPositionForView(this);    
  10.             final long id = adapterView.getItemIdAtPosition(position);    
  11.             if (isLongClick) {    
  12.                 if (adapterView.getOnItemLongClickListener() != null)    
  13.                     adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);    
  14.             } else {    
  15.                 if (adapterView.getOnItemClickListener() != null)    
  16.                     adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);    
  17.             }    
  18.         }    
  19.     }    

这里先提一下,以后会详细说怎么用的.....

github地址:

https://github.com/traex/RippleEffect

相关文章
|
1月前
|
机器学习/深度学习 Android开发 数据安全/隐私保护
手机脚本录制器, 脚本录制器安卓,识图识色屏幕点击器【autojs】
完整的UI界面,包含录制控制按钮和状态显示 屏幕点击动作录制功能,记录点击坐标和时间间隔
|
4月前
|
XML Android开发 数据格式
Android利用selector(选择器)实现图片动态点击效果
本文介绍了Android中ImageView的`src`与`background`属性的区别及应用,重点讲解如何通过设置背景选择器实现图片点击动态效果。`src`用于显示原图大小,不拉伸;`background`可随组件尺寸拉伸。通过创建`selector_setting.xml`,结合`setting_press.xml`和`setting_normal.xml`定义按下和正常状态的背景样式,提升用户体验。示例代码展示了具体实现步骤,包括XML配置和形状定义。
189 3
Android利用selector(选择器)实现图片动态点击效果
|
6月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
560 29
|
6月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
161 15
|
6月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
6月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
170 4
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
6月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
6月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
2月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
141 11

推荐镜像

更多