Android材料设计动画之触摸反馈

定制触摸反馈

前言

在Android 5.0版本发布时,所公布的Android材料设计之动画更新幅度很大,有各种各样,各种场景下的动画。动画对于增强用户体验的感受有着超级重要的贡献,为APP适量添加合适的动画,会让APP“生龙活虎”,焕发APP的活力。不仅能给用户带来超棒的视觉享受,也能增强人机交互的能力,最终带给用户一流的用户体验。

在Android 5.0发布了一个触摸反馈的动画,即当用户触摸(点击、长按)应用的控件的时候,会有一个持续一小段时间的动画,表示设备已经接收到这一用户操作便以实时动画反馈用户。

本文的demo继续使用文章《 Android材料设计》一文中的demo。

如何使用触摸反馈

触摸反馈在Android 5.0之前的老版本就有,只不过这是一种静态的反馈,那就是State list,我们把一个控件的状态以seletor为标签定义在xml文件中,如下:

<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_focused="true" android:drawable="@android:color/holo_green_dark"/><item android:state_pressed="true" android:drawable="@android:color/holo_green_dark"/><item android:drawable="@android:color/holo_blue_bright"/>
</selector>

正常状态时显示的颜色为holo_blue_bright,按下状态显示的颜色为holo_green_dark。在控件不同的状态下,显示不同的背景颜色。

在Android 5.0推出一种新的触摸反馈,波纹动画,较之前的State list,不仅有颜色的变化,还有一个波纹样式的动画持续一小段时间。

在Android 5.0后,不需要任何特殊代码,控件默认采用这种波纹动画作为控件的触摸反馈,以点击的地方为中心,有水波波纹向四周扩散。如下图是一个Button控件默认情况下的点击效果:

定制触摸反馈动画

Android提供的默认的样式往往不能满足我们的需求,这时就需要对样式等进行定制。这里说的定制,不是定制动画的样式,即不能改变波纹动画,而是对动画开始前的颜色,以及波纹的范围和颜色等进行定制。

定制波纹颜色

修改默认的触摸反馈波纹的颜色,重写主题的android:colorControlHighlight 属性即可,如下:

<resources><!-- Base application theme. --><style name="AppTheme" parent="@style/AppThemeBase"><!-- Customize your theme here. --><!-- 修改波纹颜色,使用主色调colorPrimary #3F51B5 深蓝色 --><item name="android:colorControlHighlight">@color/colorPrimary</item><item name="android:navigationBarColor">@color/navigationBarColor</item></style>
</resources>

效果如下:

定制波纹边界

把控件的background属性的值设置成如下:

  • ?android:attr/selectableItemBackground 指定波纹有边界,即波纹只在控件的范围内,默认值。
  • ?android:attr/selectableItemBackgroundBorderless 指定越过视图边界的波纹。 它将由一个非空背景的视图的最近父项所绘制和设定边界。API 级别 21 中推出的新属性

有边界的效果就是上一章节中的的图示,越过控件边界的代码如下:

<Button
    android:layout_width="match_parent"android:layout_height="wrap_content"android:textAllCaps="false"android:background="?android:attr/selectableItemBackgroundBorderless"android:textColor="@color/colorPrimary"android:text="@string/button_text"/>

效果如下:

长按的效果如下:

用xml代替

上两章节中,定义波纹颜色要在主题中,定义波纹范围在控件属性中,这样在修改和维护都不方便,可以把它们都统一写在一个xml文件中。和State list类似的selector类似,波纹动画也可以在drawable目录下创建一个ripple文件,如下:

<ripple android:color="@color/colorPrimary"xmlns:android="http://schemas.android.com/apk/res/android"><item android:id="@android:id/mask"android:drawable="@android:color/holo_green_light" />
</ripple>

android:color=”@color/colorPrimary表示波纹的颜色,作用和android:colorControlHighlight一样。

item表示正常状态的颜色,即没有press/focus的状态。

android:id=”@android:id/mask”表示是否显示item的颜色,有android:id=”@android:id/mask”表示默认不显示item的颜色,相反显示item的颜色

如果没有item,表示波纹边界越过控件,类似?android:attr/selectableItemBackgroundBorderless。如下:

<ripple android:color="@color/colorPrimary"xmlns:android="http://schemas.android.com/apk/res/android">
</ripple>

注意:触摸反馈波纹动画是Android 5.0材料设计的组成部分,所以如果APP需要兼容Android 5.0之前的版本,需要考虑兼容性。需要把相关代码放置value-v21中。

波纹动画的原理

我们知道,一个view有图像需要绘制时,会回调draw()方法,draw()方法再调用Drawable的draw()方法,把图像绘制出来。波纹动画有RippleDrawable负责绘制,RippleDrawable继承LayerDrawable,继承Drawable,当点击一个控件时,调用RippleDrawable的draw()方法绘制波纹,如下:

public void draw(@NonNull Canvas canvas) {pruneRipples();......drawContent(canvas);//绘制波纹drawBackgroundAndRipples(canvas);canvas.restoreToCount(saveCount);
}

这个方法定义在文件frameworks/base/graphics/java/android/graphics/drawable/RippleDrawable.java中。

接着调用drawBackgroundAndRipples()方法,接着看:

private void drawBackgroundAndRipples(Canvas canvas) {final RippleForeground active = mRipple;final RippleBackground background = mBackground;final int count = mExitingRipplesCount;......final int halfAlpha = (Color.alpha(color) / 2) << 24;final Paint p = getRipplePaint();......if (background != null && background.isVisible()) {background.draw(canvas, p);}if (count > 0) {final RippleForeground[] ripples = mExitingRipples;for (int i = 0; i < count; i++) {ripples[i].draw(canvas, p);}}......
}

这个方法定义在文件frameworks/base/graphics/java/android/graphics/drawable/RippleDrawable.java中。

上面的代码,有一个RippleBackground和一个RippleForeground,RippleBackground是用于绘制Ripple的背景的,单击控件时,我们看到的波纹动画由RippleForeground绘制。调用getRipplePaint()获取到画波纹的画笔,如果count > 0,就调用ripples[i].draw()方法。count表示波纹的计数,1表示一次波纹,2表示2次波纹,最多10次波纹,这里count = 1。继续往下看RippleForeground的draw()方法:

public boolean draw(Canvas c, Paint p) {......if (hasDisplayListCanvas) {final DisplayListCanvas hw = (DisplayListCanvas) c;startPendingAnimation(hw, p);if (mHardwareAnimator != null) {return drawHardware(hw);}}return drawSoftware(c, p);
}

这个方法定义在文件frameworks/base/graphics/java/android/graphics/drawable/RippleComponent.java中。

上面这个方法,会判断是否用硬件加速,如果是调用drawHardware(hw),如果不是调用drawSoftware(c, p),对于上层,它们没有区别,这两个方法,最终都是调用Canvas的drawCircle()方法,即画一个圆,这个圆表示波纹最先开始的第一道波纹,然而它是静止的,通过调用startPendingAnimation(hw, p)方法,让这个波纹从第一道波纹逐渐向四周扩散,看起来就和现实生活中的波纹的效果一样。startPendingAnimation(hw, p)的实现如下:

private void startPendingAnimation(DisplayListCanvas hw, Paint p) {if (mHasPendingHardwareAnimator) {mHasPendingHardwareAnimator = false;mHardwareAnimator = createHardwareExit(new Paint(p));mHardwareAnimator.start(hw);......}
}

这个方法定义在文件frameworks/base/graphics/java/android/graphics/drawable/RippleComponent.java中。

这里直接调用了createHardwareExit()方法创建一个RenderNodeAnimatorSet对象,然后调用start()方法启动动画,createHardwareExit()的实现如下:

protected RenderNodeAnimatorSet createHardwareExit(Paint p) {//波纹的幅度,即一个圆final int radiusDuration;//波纹持续的时间final int originDuration;//波纹的模糊度final int opacityDuration;if (mIsBounded) {computeBoundedTargetValues();radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;originDuration = BOUNDED_ORIGIN_EXIT_DURATION;opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;} else {radiusDuration = getRadiusExitDuration();originDuration = radiusDuration;opacityDuration = getOpacityExitDuration();}//波纹开始的坐标,即点击的地方final float startX = getCurrentX();final float startY = getCurrentY();final float startRadius = getCurrentRadius();//设置波纹的透明度p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f));mPropPaint = CanvasProperty.createPaint(p);mPropRadius = CanvasProperty.createFloat(startRadius);mPropX = CanvasProperty.createFloat(startX);mPropY = CanvasProperty.createFloat(startY);final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);radius.setDuration(radiusDuration);radius.setInterpolator(DECELERATE_INTERPOLATOR);final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);x.setDuration(originDuration);x.setInterpolator(DECELERATE_INTERPOLATOR);final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);y.setDuration(originDuration);y.setInterpolator(DECELERATE_INTERPOLATOR);final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,RenderNodeAnimator.PAINT_ALPHA, 0);opacity.setDuration(opacityDuration);opacity.setInterpolator(LINEAR_INTERPOLATOR);opacity.addListener(mAnimationListener);final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();set.add(radius);set.add(opacity);set.add(x);set.add(y);return set;
}

这个方法定义在文件frameworks/base/graphics/java/android/graphics/drawable/RippleForeground.java中。

上面的代码对应radius,x,y,opacity实例化一个RenderNodeAnimator对象,表示是一个动画,然后把每个动画add()到动画的集合中,这个和Android其它常用的动画使用是基本类似的。再往下就是动画的原理了,不在本文阐述的范围,读者可以查阅相关的Android动画的显示过程的资料。

Android材料设计动画之触摸反馈相关推荐

  1. Android材料设计

    Android材料设计 Android Material Design Android倡导UI设计 前言 2014年的Google I/O大会上隆重发布了Android 5.0,从Android 4. ...

  2. Android材料设计之材料主题

    Android材料设计之材料主题 Android Material Design Theme Android 主题 前言 在上一篇文章<Android材料设计>一文中,对Android材料 ...

  3. Android 材料设计Material Design 动画篇(一)

    Material Design,中文名:材料设计语言,是由Google推出的全新的设计语言,谷歌表示,这种设计语言旨在为手机.平板电脑.台式机和"其他平台"提供更一致.更广泛的&q ...

  4. android材料设计层次,Android材料设计之ToolBar+CardView

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 皑如山上雪,皎若云间月. ToolBar 常用属性1 2 3 4 5 6背景------android:backgrou ...

  5. Android: Kotlin 材料设计入门

    原文:Android: Kotlin 材料设计入门 作者:Joe Howard 译者:kmyhy 更新说明:本教程由 Joe Howard 升级为 Kotlin.原教程作者是 Megha Bambra ...

  6. Android复习15【动画:创建资源文件夹、创建动画资源文件、组合动画、属性动画、材料设计新特性】

    2020-05-09-[12周-周四] Android动画 https://blog.csdn.net/zhangbijun1230/article/details/80262359 https:// ...

  7. Material Design之定制动画--触摸反馈,循环揭露,转场动画,共享元素和曲线运动

    先贴下官网的API https://developer.android.com/training/material/animations.html 触摸反馈: 在按钮属性中添加 android:bac ...

  8. android app底部菜单栏,材料设计指南·组件篇(一):AppBars: Bottom 底部栏

    写在前面的话:内容来自 Material IO ,目前不是从头到尾一一翻译,我自己用到哪部分内容就翻译哪部分.之后会逐步完善,当然你要想先看哪部分也可以留言提要求.不是直译,但不会影响原文内容. 材料 ...

  9. android触摸效果,Android开发进阶:仿MIUI12控件触摸反馈效果(下沉+倾斜)附源码...

    简单模仿了下MIUI12里控件的触摸反馈效果,转载请标明出处 效果简述 按压控件内圈区域,控件整体缩小,高度降低(阴影消失) 按压内圈 按压控件外圈区域,依据触摸点控件以中心为支点,向触摸点倾斜 按压 ...

最新文章

  1. Topo系统的益处和帮助
  2. java string字节数组_java(基本类型或者String字符串)与(字节数组)相互转换
  3. Dubbo面试题锦集
  4. [unity3d]自定义鼠标指针
  5. 思科修复 ASA/FTD 防火墙高危缺陷,已遭利用
  6. 学习Mahout(二)
  7. 设计模式之GOF23模板模式
  8. 黑马程序员-IT学生解惑真经-想做程序员或者正在迟疑的同学可以看一下,很有帮助的一篇文章
  9. 圣彼得堡三大教堂_2020年9大最佳教堂网站建设者(适合初学者)
  10. 利用批处理文件快速设置IP地址
  11. 生产系统规划仿真软件
  12. 【代码小记】赏析《RAFT:运动属性的光流感知》
  13. 10g ASM下加控制文件 .
  14. 第1章 初识软件工程
  15. 集合——List集合
  16. 社区运营秘笈:病毒式营销!
  17. 联想计算机如何进bois,小编教你联想电脑怎么进入bios
  18. CentOS上安装Web性能测试工具Siege 示例
  19. 酷狗音乐皮肤怎么从计算机里换,酷狗音乐该怎样换皮肤?
  20. Java/JDK安装与环境配置教程

热门文章

  1. 科研日记2——APS讲解论文写作
  2. 数据交换格式 - PB(protocol buffer),xml,json,array
  3. “终于我从字节离职了...“一个年薪40W的测试工程师的自白..
  4. 谷歌(chrome)浏览器设置成深色模式(dark)
  5. 【Realflow】Daemons - Gravity节点翻译
  6. 张孝祥老师给我们上课之后的感想
  7. iOS开发常用第三方开源框架
  8. Servlet过滤器概念特点等详谈
  9. Android 部分 Broadcast 篇
  10. 被窝网告诉你:商标转让与许可哪个更合算