首先来复习下属性动画相关知识:

Android属性动画(一)—— 属性动画的基本使用_Marck的博客-CSDN博客_android 属性动画

Android属性动画(二)—— 插值器和估值器_Marck的博客-CSDN博客_属性动画插值器估值器

一、结论:

属性动画:所见即所得,最终的显示位置变了,坐标也变了;
补间动画:所见并非所得,虽然最终的显示位置变了,但是坐标还是之前的。

每日一问:谈谈属性动画和补间动画的原理及区别 - 简书

二、属性动画和补间动画的基本编写方式

我一度在论坛上看到人使用了 TranslateAnimation 对控件做了移动操作,然后发现在 View 的新位置点击并没有响应自己的点击事件,反倒是之前的位置能够响应。实际上,补间动画仅仅是对 View 在视觉效果上做了移动、缩放、旋转和淡入淡出的效果,其实并没有真正改变 View 的属性。但我们大多数情况下肯定希望 View 在经过动效后响应触摸事件的位置和视觉效果相同,所以在 Android 3.0 之后引入了属性动画,彻底解决了这个难题。

可能还有一些小伙伴不明白怎样的代码是属性动画,怎样的代码是补间动画。下面针对 View 向右平移 500 px 做一下简单的演示。

对于属性动画,你可以用下面的两种方式。

ObjectAnimator.ofFloat(tv1, "translationX", 0f, 500f).setDuration(1000).start()
// 或者像这样
tv1.animate().setDuration(1000).translationX(500f)

但用补间动画,并且你想达到同样的效果的话。

val anim = TranslateAnimation(0f, 500f, 0f, 0f)
anim.duration = 1000
anim.fillAfter = true    // 设置保留动画后的状态
tv1.startAnimation(anim)
  • 属性动画的使用注意点

对于属性动画来说,尤其需要注意的是操作的属性需要有 set 和 get 方法,不然你的 ObjectAnimator 操作就不会生效。比如水平平移,我们知道,View 的 translationX 属性设置方法接受的是 float 值,所以你把上面的操作编写为 ofInt 就不会生效,比如:

ObjectAnimator.ofInt(tv1, "translationX", 0, 500).setDuration(1000).start()

对于我们需要用到但又没有写好的属性,比如我们自定义一个进度条 View,我们需要实时展示进度,这时候我们就可以自己定义一个属性,并让它支持 set 和 get,那么在外面就可以对这个自定义的 View 做属性动画操作了。

属性动画和补间动画工作原理

属性动画

属性动画的工作原理很简单,其实就是在一定的时间间隔内,通过不断地对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在属性上的动画效果。

这个属性可以是任意对象的属性。

从上述工作原理可以看出属性动画有两个非常重要的类:ValueAnimator 类 & ObjectAnimator 类,二者的区别在于:
ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;而 ValueAnimator 类本质上是一种 改变值 的操作机制。

ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;可以理解为:ObjectAnimator 更加智能、自动化程度更高。

补间动画

而对于补间动画,我们不妨跟进源码,看看到底做了什么操作。

/*** Start the specified animation now.** @param animation the animation to start now*/
public void startAnimation(Animation animation) {animation.setStartTime(Animation.START_ON_FIRST_FRAME);setAnimation(animation);invalidateParentCaches();invalidate(true);
}

看到了非常明显 invalidate() 方法,很明显,补间动画在执行的时候,直接导致了 View 执行 onDraw() 方法。总的来说,补间动画的核心本质就是在一定的持续时间内,不断改变 Matrix 变换,并且不断刷新的过程。

为什么属性动画移动一个 View 后,目标位置还可以响应触摸事件呢?

这个问题来自 wanandroid,在此前,我一直认为既然 View 的属性得到了改变,那么经过属性动画后的控件应该所有属性都等同于直接设置在动画后的位置的控件。

看完「陈小缘」的回答后,我突然才想到,虽然 View 做了属性上的改变,但其实并没有更改 Viewleftrighttopbottom 这些属性,而这些属性恰恰决定了 ViewGroup 的触摸区域判断。

  • tv1.animate().setDuration(1000).translationX(500f)
    

那么,假定我们的 View 经过了上面的平移操作后,为什么点击新的位置能够响应到这个点击事件呢?

看了「陈小缘」的回答,我顺便深入了一波源码,想想必须在这分享给大家。

我们知道,在 ViewGroup 没有重写 onInterceptTouchEvent() 方法进行事件拦截的时候,我们一定会通过其 dispatchTouchEvent() 方法进行事件分发,而决定我们哪一个子 View 响应我们的触摸事件的条件又是 我们手指的位置必须在这个子 View 的边界范围内,也就是 leftrighttopbottom 这四个属性形成的矩形区域。

那么,如果我们的 View 已经进行了属性动画后,现在手指响应的触摸位置区域肯定不是 View 自己的leftrighttopbottom 这四个属性形成的区域了,但这个 View 却神奇的响应了我们的点击事件。

/*** Returns a MotionEvent that's been transformed into the child's local coordinates.** It's the responsibility of the caller to recycle it once they're finished with it.* @param event The event to transform.* @param child The view whose coordinate space is to be used.* @return A copy of the the given MotionEvent, transformed into the given View's coordinate*         space.*/
private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {final float offsetX = mScrollX - child.mLeft;final float offsetY = mScrollY - child.mTop;final MotionEvent transformedEvent = MotionEvent.obtain(event);transformedEvent.offsetLocation(offsetX, offsetY);if (!child.hasIdentityMatrix()) {transformedEvent.transform(child.getInverseMatrix());}return transformedEvent;
}/*** Returns true if the transform matrix is the identity matrix.* Recomputes the matrix if necessary.** @return True if the transform matrix is the identity matrix, false otherwise.*/
final boolean hasIdentityMatrix() {return mRenderNode.hasIdentityMatrix();
}/*** Utility method to retrieve the inverse of the current mMatrix property.* We cache the matrix to avoid recalculating it when transform properties* have not changed.** @return The inverse of the current matrix of this view.* @hide*/
public final Matrix getInverseMatrix() {ensureTransformationInfo();if (mTransformationInfo.mInverseMatrix == null) {mTransformationInfo.mInverseMatrix = new Matrix();}final Matrix matrix = mTransformationInfo.mInverseMatrix;mRenderNode.getInverseMatrix(matrix);return matrix;
}

原来,ViewGroupgetTransformedMotionEvent() 方法中会通过子 ViewhasIdentityMatrix() 方法来判断子 View 是否应用过位移、缩放、旋转之类的属性动画。如果应用过的话,那还会调用子 ViewgetInverseMatrix() 做「反平移」操作,然后再去判断处理后的触摸点是否在子 View 的边界范围内。

补间动画和属性动画改变的是同一个 Matrix 么?

负责任的说:肯定不是。

属性动画所影响的 Matrix,是在 ViewmRenderNode 中的 stagingProperties 里面的,这个 Matrix 在每个 View 之间都是独立的,所以可以各自保存不同的变换状态。

而补间动画所操作的 Matrix,其实是借用了它父容器的一个叫 mChildTransformation 的属性 ( 里面有 Matrix ),通过 getChildTransformation 获得。
也就是说,一个 ViewGroup 中,无论它有几个子 View 都好,在这些子 View 播放补间动画的时候,都是共用同一个 Transformation 对象的(也就是共用一个 Matrix ),这个对象放在 ViewGroup 里面。

有同学可能会问:共用?不可能吧,那为什么可以同时播放好几个动画,而互相不受影响呢?
是的,在补间动画更新每一帧的时候,父容器的 mChildTransformation 里面的 Matrix,都会被 reset()

每次重置 Matrix 而不受影响的原因:
是因为这些补间动画,都是基于当前播放进度,来计算出绝对的动画值并应用的,保存旧动画值是没有意义的。
就拿位移动画 TranslateAnimation 来说,比如它要向右移动 500,当前的播放进度是 50%,那就是已经向右移动了 250,在 View 更新帧的时候,就会把这个向右移动了250的 Matrix 应用到 Canvas 上,当下次更新帧时,比如进度是 60%,那计算出来的偏移量就是 300,这时候,已经不需要上一次的旧值 250 了,就算 Matrix 在应用前被重置了,也不影响最后的效果。

感叹,今天又发现了一些非常通用却被我们忽略掉的东西,不得不说,鸿洋的 wanandroid 带给了我们很多东西,更加惊叹的是「陈小缘」同学的 View 相关功底确实很强,这也难怪,他能写出如何有逼格的自定义 View 了。

View 相关的非常渴望了解的可以到小缘的博客去一探究竟。 https://me.csdn.net/u011387817

属性动画和补间动画的原理及区别相关推荐

  1. 属性动画、帧动画、补间动画的介绍使用及对比

    属性动画.帧动画.补间动画的介绍使用及对比 版权声明:转载必须注明本文转自南轩的博客: http://blog.csdn.net/nanxuan521 在android开发中经常会碰到一些动画需求,其 ...

  2. 属性动画、帧动画、补间动画

    补间动画(Tween Animation) 1.补间动画的特性: a.渐变动画支持四种类型:平移(Translate).旋转(Rotate).缩放(Scale).不透明度 b. 只是显示的位置变动,V ...

  3. Android动画(帧动画、补间动画、属性动画)讲解

    Android动画(帧动画.补间动画.属性动画)讲解 首先我们来看看啥是帧动画.补间动画.属性动画. 介绍: 帧动画:是一种常见的动画形式(Frame By Frame),其原理是在"连续的 ...

  4. 帧动画(FrameAnimation) 补间动画(TweeAnimation) 属性动画(ObjectAnimation)

    帧动画 Frame Animation是顺序播放事先做好的图像,跟电影类似.不同于animation package,Android SDK提供了另外一个类AnimationDrawable来定义使用 ...

  5. android属性动画替换逐帧动画,Android 动画:逐帧动画,补间动画和属性动画

    1.三种动画的介绍 现在 Android 常用的动画有三种: 逐帧动画,补间动画和属性动画: FrameAnimation(逐帧动画):将多张图片组合起来进行播放,很多 App 的加载动画是采用这种方 ...

  6. Android 三种动画 (帧动画 、补间动画、属性动画)

    1.帧动画 帧动画是依次展示n张静态图片,造成动画的错觉,类似看视频一样. 使用方式 在drawable目录下定义XML文件,根节点为animation-list,然后放入定义更好的图片 onesho ...

  7. Android帧动画特点,Android帧动画和补间动画看这篇足够了

    原标题:Android帧动画和补间动画看这篇足够了 距离活动开始还有两天,重庆的开发者们赶快报名行动起来吧! 写在前面 为了使用户的交互更加流畅自然,动画也就成为了一个应用中必不可少的元素之一.在 A ...

  8. 帧动画和补间动画看这篇足够了

    帧动画和补间动画看这篇足够了 本文原创,转载请注明出处. 欢迎关注我的 简书 ,关注我的专题 Android Class 我会长期坚持为大家收录简书上高质量的 Android 相关博文. 写在前面: ...

  9. android 帧动画张数限制,Android帧动画和补间动画看这篇足够了

    原标题:Android帧动画和补间动画看这篇足够了 写在前面 为了使用户的交互更加流畅自然,动画也就成为了一个应用中必不可少的元素之一.在 Android 中常用的动画分类无外乎三种,最早的帧动画.补 ...

  10. Android动画之帧动画和补间动画

    Android系统提供三种动画:帧动画.补间动画和属性动画.这里先分析总结帧动画和补间动画. FrameAnimation 帧动画,通俗来说就是按照图片动作顺序依次播放来形成动画,创建帧动画可以用 x ...

最新文章

  1. dma接收双缓存 stm32_容易被大多数人忽视的STM32串口DMA问题
  2. 一条光纤的传输容量高达 661Tbps(附论文)
  3. mysql 数据库事务处理_MySQL数据库事务及其原理
  4. ❤️拿到offer的成长之路与经验感悟分享❤️
  5. OBD技术速成——J1850协议概述
  6. Jzoj4891 摆书
  7. 10.13 上午 考试
  8. Spring对AspectJ的支持
  9. Git安装及密钥的生成并上传本地文件到GitHub上
  10. 策略模式Strategy——坐什么车回家?
  11. Unity3D基础34.1:打砖块小游戏优化
  12. Ajax提交json数据,通过jquery.cookie.js插件解决csrf_token问题
  13. BZOJ2281 [SDOI2011]黑白棋 【dp + 组合数】
  14. Snake算法知识点记录
  15. 微信模板消息的发送动态封装(Java完美封装)
  16. springboot酒店客房预定管理系统
  17. Java:计算圆的面积和周长
  18. iPad----------教你如何查询ipad型号
  19. 华为鸿蒙系统操作教程_华为鸿蒙系统2.0怎么安装 鸿蒙系统2.0安装教程[多图]
  20. Pure-ftpd 安装笔记

热门文章

  1. dw中html5快捷键,Adobe Dreamweaver(dw)常用快捷键--系统之家
  2. Mysql如何跨库查询数据?
  3. 奇计淫巧______bitset优化
  4. python数据爬虫代码_Python实现爬虫爬取NBA数据功能示例
  5. js 条码枪扫描_JavaScript 扫描枪使用(一)
  6. UWP 如何访问本地代理
  7. matlab画伯德图(带谐振点和-3dB带宽)
  8. 固态硬盘能不能提高计算机速度,固态硬盘掉速如何解决?几招轻松提升SSD速度方法 (全文)...
  9. 【Python】国内生产总值分析预测
  10. R语言数据统计1——正态性检验