android动画原理笔记(动画的本质+使用)

动画:概念简单、细节多

本质:

两个状态的平滑过渡
比如:

	imageView.setTranslationX(500);

刷得一下就过去了,没有动画
动画就是在一定时间内,不断地调用setTranslationX一点一点的靠近,这个过程要在子线程中进行
下面写一个演示属性动画原理demo

final float[] newTranslation = {0};
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        //每次向右移动 5 像素, 100 次就是 500 像素
        newTranslation[0] += 5;
        tv.setTranslationX(newTranslation[0]);
    }
};

for (int i = 0; i < 100; i++) {
    //每 10 毫秒改变一次位置,反复 100 次
    tv.postDelayed(runnable , i*10);
}

可以看出,这样做起来很麻烦,要考虑他要移动多远,要花多少时间,然后根据这个去计算他要移动多少步,每一步要移动多少距离。
这是你能想到的,还有你想不到的。比如,在动画移动到一半的时候,用户如果点击一个按钮,动画要瞬间取消,怎么取消?
或者是我希望这个动画不要是一个匀速的过程,我希望他是一个减速的过程。这种情况他的速度曲线怎么算,每一个时间点他所对应的位置是哪?不好算
还有就是我希望这个动画在结束的时候给我一个通知,我去做一些用户的界面通知或者资源回收这种工作,那么这个监听器怎么设?
理论上来说,这些都是可以通过代码来实现的,但是太麻烦了,如果你用属性动画的API,可能一行代码或者几行代码就可以做出来了
这就是属性动画API他的作用,他很方便

属性动画里最简单的是ViewPropertyAnimator

他的使用方法很简单,你调用View.animate()然后再加几行代码描述一下就可以了
比如你想让view向右移动500像素,只要加一句translationX(500)就可以了

ianmgeView.animate().translationX(500);

你在调用这行代码以后,他就会每隔10ms调用一次View.setTranslationX()方法,把View一点点往右挪,直到挪到目标位置。整个过程是自动的。这个就是ViewPropertyAnimator。
在这可能有的人要问了,你说的这个ViewPropertyAnimator是个什么东西啊?我在代码里怎么没有看见呢?
其实, 你在调用View.animate()的时候,返回的就是一个ViewPropertyAnimator对象,只不过我没有在代码里把他赋值给一个变量。
另外,有有的人可能会问,你说的这个每隔10ms自动调用一次的这个View.setTranslationX()方法是什么呢?
其实这也不是什么新东西了,他在android3.0也就是API 11的时候就出现了。他的作用就是给View设置横向的位置偏移。
比如,按照你的layout文件, 你的某一个View的横坐标应该是100像素,那么你调用View.setTranslationX(50),他的实际横坐标就会忘右挪50,也就是150像素。这个方法有什么用呢?用来做动画。他就是为动画而生的。在动画之外,他的使用场景还真是不多。这也是为什么这个方法这么历史悠久了,但是很多人不知道的原因。和这个方法一起在Android3.0也就是API 11诞生的方法有十几个 。
在这里插入图片描述
你写多个方法就可以改变多个属性。

imageView.animate().scaleX(1).scaleY(1).alpha(1);
//放大的同时改变透明度,做一个弹出效果、

动画执行的默认时间是0.3秒,可以通过setDuration(500);参数是毫秒

速度模型

除了时长还可以设置速度模型,加速,减速,匀速。设置速度模型就是setInterpolator()方法。他的参数是一个interpolator。interpolator这个词他在生活里面是用不到的。他是一个数学上的词,他的中文可以叫做内插器或者插值器。内插的意思就是对一段离散的数据点上面的每一个值去求他们对应的另外一个值。具体的意思:对于android的动画来说,这个内插他的意思就是根据你的时间完成度去计算他所对应的动画完成度。
默认的Interpolator叫做AccelerateDecelerateInterpolator,他是在开始加速,在结束减速的速度模型。
其他速度模型讲义里面有。

监听器

动画开始动画结束,动画更新
在这里插入图片描述
上面讲的就是ViewPropertyAnimator,他简单好用,但是只能使用他提供给你的那几个属性,在这之外的属性是操作不了的。

ObjectAniamtor

ObjectAnimator与ViewPropertyAnimator最大的区别就是可以自定义属性。
他的使用比较麻烦。
首先,他的属性需要你在创建Animator对象的时候就把他确定下来,而不能像ViewPropertyAnimator那样随写随用,随用随写。
另外,他的动画开始不能是自动的。你需要主动地去调用它的start()方法。
我依然用横向平移举例,如果用ObjectAnimator怎么做呢?

ObjectAnimator translationX = ObjectAnimator.ofFloat(tv, "translationX", 500);
translationX.start();

好像也不是很麻烦。说一下这个ofFloat()方法
ObjectAnimator的使用方式是使用一系列of- 打头的方法
在这里插入图片描述
其中Int、Float等指的是属性的类型。
比如我横向移动调用的是View的setTranslationX()方法,他的参数是float类型的,你们我就用ofFloat()来创建Animator。他的第一个参数是目标对象,他的第二个参数是
对象的哪个属性要做动画。是属性的名字,是一个字符串。第三个参数是属性的目标值,这个属性值可以填一个也可以填多个。如果填一个就是目标值,如果填两个就是起始值和目标值。填多个的话就是起始值、中间各个转接点的值、目标值。
不过这里需要说一下的是,他并不是直接用你填的这个字符串去找对象里面的同名变量,而是会根据你填的变量名,来拼接出他的setter方法,然后调用这个方法(估计是用的反射)。
这个行为逻辑和之前将的ViewPropertyAnimator是一致的。他们都是调用setter方法,而不是直接去修改这个属性值,这种做法的好处是,setter方法里面你可以插一些额外的操作。比如刷新界面,也就是重绘。
这样用起来感觉不难,不过这个只是针对已经有了setter方法的属性,如果你要对你自己的自定义属性来做动画的话,你需要为属性添加setter方法。另外,如果你在ofFloat()或者of- 什么什么的方法的属性值参数只有一个的话, 你就还要一个getter方法,因为只有一个参数就只有目标值,还需要一个起始值,就是通过getter方法获取到你的当前值作为起始值。
在这里插入图片描述
举个例子:比如我写了一个SportsView,他有一个图像展示运动量,我想针对他的运动量这个属性progress来做动画。
那么,我需要三步。
1.给SSportsView增加setProgress()和getProgress()两个方法。
2.用ofFloat()来创建一个Animator对象
3.调用start()来执行动画
然后他就会反复地调用setProgress()方法来展现动画,不过你会发现这样做了之后点击按钮并没有反应,这是为什么?
不是因为你的代码写错了,而是你的setter方法没有写完整。
在这里插入图片描述
Android里面界面的绘制都是被动的。你让他绘制才会绘制,你的setter方法里面如果只是修改了属性的值,那么他是不会自动重绘的。也就是说他的draw()方法是不会被自动调用的。要想让界面及时的重绘,你就需要在属性改变之后主动地去通知界面重绘。通知的方式很简单,一行的代码:invalidate();
invalidate()这个方法相当于是一个重绘的指令,他会把你之前的绘制的内容标记为失效,然后当下一帧到来的时候,你的View就不会继续沿用上一帧的内容,而是会自动调用他的draw()方法,把内容重新绘制一遍。
另外前面讲到的ViewPropertyAnimator,他的内部实现所调用的那些View.setTranslationsX()方法,他们内部也是加了界面的刷新的。不过他们的实现方式更高效一点,他们并没用调用invalidate()这个方法,而是使用另外一种方法,借助硬件加速没有重绘界面,不用重绘界面就实现了界面的刷新,非常的高效。这个自定义绘制是不能用的。
总结:
在这里插入图片描述贴上大佬的视频和讲义
https://www.bilibili.com/video/av14207821?zw
https://hencoder.com/ui-1-6/

猜你喜欢

转载自blog.csdn.net/qq_36333289/article/details/91443487