Android动画了解—属性动画(Property Animation)

属性动画

在这里插入图片描述
属性动画(Property Animation) 是 API Level 11 时被引入的,Android 3.0 才开始有 属性动画相关的 API.

先来看看网上的一个开源控件,动画还是很酷炫,基本包含了属性动画该有的大部分知识内容.
在这里插入图片描述
在这里插入图片描述

1. ValueAnimator

ValueAnimator是属性动画的核心类,下面会讲到 TimeAnimator, ObjectAnimator 就是它的子类。

调用的几个方式
ofObject是直接把一个对象过渡到另外一个对象,其它的 ofArgb/ofFloat/ofInt 是将值过渡到另一个值
ValueAnimator.ofObject(TypeEvaluator evaluator/*估值器,下个章节有介绍*/, Object... values)
ValueAnimator.ofArgb(int... values)
ValueAnimator.ofFloat(float.. values)
ValueAnimator.ofInt(int... values)
ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder... values)

举个栗子

// ValueAnimator.ofObject demo 
ValueAnimator objectAnimator = ValueAnimator.ofObject(
                new PointEvaluator(), new Point(10, 10), new Point(100, 100));
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
    
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
    
    
                mPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
});
objectAnim.setDuration(2000);
objectAnim.setRepeatCount(ValueAnimator.INFINITE);
objectAnim.setRepeatMode(ValueAnimator.RESTART);
objectAnim.start(); // 启动动画
                        
# 刷新UI绘制界面
@Override
protected void onDraw(Canvas canvas) {
    
    
	canvas.drawCircle(mPoint.x, mPoint.y, 50, mPaint);
}    

在这里插入图片描述

涉及的知识点

函数名 说明
Animator.start() 启动动画
Animator.end() 结束动画
Animator.cancel() 取消动画
Animator.pause() 暂停动画 API 19新增的方法
Animator.resume() 重新启动 API 19新增的方法
Animator.setDuration(int) 设置动画时间
setRepeatCount(int) 动画重复次数(大于等于 0),值为 小于0 或 ValueAnimator.INFINITE 时,无限循环
setRepeatMode 设置循环模式,ValueAnimator.RESTART: 重新从头开始执行 ;ValueAnimator.REVERSE:反方向执行
addUpdateListener 监听数值变化, ValueAnimator.AnimatorUpdateListener -> onAnimationUpdate 通过数值返回进行一序列相关操作
动画监听器 addListener Animator.AnimatorListener 相关函数说明: onAnimationStart() - 在动画开始播放时调用;onAnimationEnd() - 在动画结束播放时调用/取消的动画也会调用; onAnimationRepeat() - 在动画重复播放时调用;onAnimationCancel() - 在动画取消播放时调用;

像几年前在公司写的输入法的移动边框的动画,就是用的 ValueAnimator + onDraw绘制(onAnimationUpdate更新相关值) 出来的动画效果
在这里插入图片描述
其实有一些酷炫的动画(当然这里你需要了解android绘图的相关知识(比如绘图,混合模式,Canvas,Paint等等),也是用这种方式弄出来的.

https://zhuanlan.zhihu.com/p/101794514
感兴趣的朋友 参考 官方资料搜索相关资料

在这里插入图片描述
资料学习地址

还有一个很酷炫的爆炸粒子效果
在这里插入图片描述
相关资料学习地址

1.1 ObjectAnimator

ValueAnimator 有一个缺点,如果对某个控件执行动画,就需要监听 ValueAnimator 的动画过程,相比补间动画(View动画)要繁琐的多。

为了调用简单方便的去 动画对应的控件,所以就产生了 ObjectAnimator(继承自ValueAnimator,所以ValueAnimator的函数ObjectAnimator都可以调用) ;

ObjectAnimator 重写了几个函数,ofInt()ofFloat(object target, String propertyName, float... values)ofArgb() 等等;来看看函数的使用方式的小栗子;

实现了 放大 X 的动画

// 第一个参数传入需要做动画的对象(target) 第二个参数 是属性,第三个参数是 可变参数,是值.
// 现在就是 放大 X,从 1.0f ~ 2.4f 
// 之所以可以动画,是因为 view 里面有  setScaleX(float scaleX) 这个函数,ObjectAnimator对这个 view 的 scaleX 自动赋值.
ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.SCALE_X/*scaleX*/, 1.0f, 2.4f);
animator.setDuration(300);
animator.start();

在这里插入图片描述
ObjectAnimator动画流程了解
ofFloat(view, “scaleX”, 1.0f, 2.4f) -> 插值器 -> 估值器 -> 调用set函数(主要是反射+拼装)

可以改变的控件属性列表scaleXscaleYtranslationXtranslationYalpharotation 等等。(主要是类里面可以设置的属性值,都可以改变,需要有 setXXX才行)

旋转
在这里插入图片描述
我们还可以自定义ObjectAnimator

  • 为对象设置需要操作属性的 set()get() 方法
  • 通过实现 TypeEvaluator(估值器) 类从而定义属性变化的逻辑(下下个章节有介绍)

来个小栗子(我们修改刚才的ValueAnimatror小球的移动的代码)

// 1. 给小球的View的类 添加了一个带 SetXXX 方式的函数
public void setPointX(int x) {
    
    
	mPoint.x = x;
    invalidate();
}

// 2. 因为是 int 类型,所以使用 ofInt
ObjectAnimator testAnim = ObjectAnimator.ofInt(view, "PointX", 100, 500);
testAnim.setDuration(888);
testAnim.start();

在这里插入图片描述
注意
如果想要改变控件的宽(Width),高(Height),是不行,因为setWidth不是改变的控件的宽度,所以需要这样改.

private static class ViewWrapper {
    
    
	private View mTarget;
	// 构造方法:传入需要包装的对象
    public ViewWrapper(View target) {
    
    
		mTarget = target;
    }

	public void setWidth(int width) {
    
    
        mTarget.getLayoutParams().width = width;
		... ..
	}
	public void setHeight(int height) ...
	... ...
}

// 调用方式
ObjectAnimator widthAnim = ObjectAnimator.ofInt(new ViewWrapper(view), "width", 100, 500);

1.2 TimeAnimator 与 其它

TimeAnimator(继承自 ValueAnimator) 不常用,此处不做篇幅介绍,感兴趣的小伙伴,请自行查阅官方文档或者搜索相关资料.

PropertyValuesHolder 官方文档资料
指定关键帧 Keyframe.ofFloat(float fraction, float value),(类似动画的关键帧,包含两个元素,时间点和位置)

// 小DEMO
// 生成了三个KeyFrame对象 
// fraction:表示当前的显示进度,即从加速器中getInterpolation()函数的返回值; 
// value:表示当前应该在的位置 
KeyFrame frame0 = Keyframe.ofFloat(0f, 10f);
KeyFrame frame1 = Keyframe.ofFloat(0.1f, 120f); 
KeyFrame frame3 = Keyframe.ofFloat(1.0f, 0f);
// 
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", frame0, frame1, frame2);  
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, rotationHolder);  
animator.setDuration(3000);   
animator.start();  

在这里插入图片描述

Android 3.1 补充了 ViewPropertyAnimator 官方文档资料

// 谷歌官方为了便捷人性化的使用动画,Android 3.1 支持ViewPropertyAnimator 的方式.
view.animate().scaleX(1.2f).scaleY(1.2f).setDuration(300).start();
// 还包含(alhpa,translationX/Y,rotationX/Y....),具体参考文档,这里不进行详细的概述~!!

AnimatorSet

前面讲解的 ValueAnimator 与 ObjectAnimator,TimeAnimator 只能单独实现一个动画,如果我们想弄出复杂的动画效果,就需要用到 AnimatorSet 将他们串联起来。
在这里插入图片描述
如何去串联,这里涉及到两个重要的函数

  • playSequentially(Animator... items | List<Animator> items): 顺序执行动画效果,这种情况类似,一分钟内 事情只能一个个来做
  • playTogether(Animator... items | Collection<Animator> items): 同时并行执行动画效果,这种情况类似,在1分钟内 同时可以做几个事情

其它相关函数了解

类名 说明
setDuration(long duration) 设置动画时长
setInterpolator 设置插值器
setTarget(Object target) 设置目标对象,需要做动画的对象

举个栗子(模仿开始的酷炫菜单 搞一个小DEMO(菜单展开).

讲解下这个小demo的思路,

  1. 每个childView 添加 翻转 + 透明 到 集合Set.(注意,这里是同时并行执行动画效果,使用的playTogether)
  2. 将所有 childView 的 集合set,添加到 总的集合allSet(这里是顺序执行动画效果,使用的 playSequentially).
  3. 最终的效果就是,childView 一个个顺序 的 同时在 翻转+透明
// 初始化位置
for (int i = 1; i < mRootLayout.getChildCount(); i++) {
    
    
	View view = mRootLayout.getChildAt(i);
	view.setPivotY(0);
	view.setRotationX(-90);
}
// 动画集合        
AnimatorSet allSet = new AnimatorSet();
List<Animator> animList = new ArrayList<>();
for (int i = 1; i < mRootLayout.getChildCount(); i++) {
    
    
	View childView = mRootLayout.getChildAt(i);
    AnimatorSet set = new AnimatorSet();
    // 同时并行执行 翻转 + 透明 的动画效果,加入集合 set
    set.playTogether(rotationOpenVertical(childView), rotationOpenAlpha(childView));
    animList.add(set);
}
// 顺序执行 childView 的动画效果,加入集合 allSet
allSet.setInterpolator(new AccelerateInterpolator());
allSet.playSequentially(animList);
allSet.setDuration(388);
allSet.start();

// 旋转
public static ObjectAnimator rotationOpenVertical(View v) {
    
    
	return ObjectAnimator.ofFloat(v, "rotationX", -90, 0);
}

// 透明
public static ObjectAnimator rotationOpenAlpha(View v) {
    
    
	return ObjectAnimator.ofFloat(v, View.ALPHA, 0, 1);
}

在这里插入图片描述

插值器(Interpolator)

设置插值器 - setInterpolator
插值器(加速器)说白了,就是 控制变化速率(指定动画如何变化变量) 的,比如 1秒(1000ms) 内 的 0 ~ 400 的距离,我们可以让这 0 ~ 400 区间 不是 匀速的,有快有慢,这就是插值器的作用;
除了下列的官方自带的插值器(参考链接1参考链接2),插值器也可以进行自定义;

类名 说明
AccelerateDecelerateInterpolator 加速减速插值器,该插值器的变化速率在 开始和结束时缓慢, 中间加速。
AccelerateInterpolator 加速插值器,动画开始的地方速率改变比较慢,然后开始加速
DecelerateInterpolator 减速插值器,动画开始的一瞬间加速到最大值,然后逐渐变慢
LinearInterpolator 线性插值器,匀速加速器
BounceInterpolator 弹跳插值器,模拟自由落地后回弹的效果
AnticipateInterpolator 初始偏移插值器,开始时 反方向移动一段距离 ,然后继续动画
OvershootInterpolator 结束偏移插值器,结束时,超出结束位置,然后再回到结束位置
CycleInterpolator 循环插值器,该插值器的动画会在指定数量的周期内重复。
AnticipateOvershootInterpolator AnticipateInterpolator + OvershootInterpolator 的组合;
TimeInterpolator 该接口自定义自己的插值器。

举个栗子
不设置插值器,默认是 LinearInterpolator(匀速),看下效果
在这里插入图片描述

以控件顺序设置,进行插值器的设置,同样的时间3秒,同样的移动距离(translationX) 0~500
new AccelerateDecelerateInterpolator(); //(红色) 加速减速插值器,该插值器的变化速率在 开始和结束时缓慢, 中间加速
new DecelerateInterpolator(); //(黄色) 减速插值器,动画开始的一瞬间加速到最大值,然后逐渐变慢
new AccelerateInterpolator(); //(绿色) 加速插值器,动画开始的地方速率改变比较慢,然后开始加速
new LinearInterpolator(); //(蓝色) 线性插值器,匀速加速器
new AnticipateInterpolator(); //(x色) 初始偏移插值器,开始时 反方向移动一段距离 ,然后继续动画

在这里插入图片描述
从例子可以看出,插值器,主要是给动画增加了变化的速率,让动画更有节奏,更好看一些,就像我们跑步一样,有时快,有时慢;

AnticipateInterpolator 的解析
在这里插入图片描述

// 原来是套入了一个数学公式 input * input * ((2.0f + 1) * input - 2.0f) 做了变化的速率
// 这样的话,如果需要弄一些其它的效果,就可以进行自定义插值器
public float getInterpolation(float input) {
    
    
	float tension = 2.0f;
	float value = input * input * ((tension + 1) * input - tension);
	return value;
}

自定义插值器小栗子

// 继承 TimeInterpolator,重写 getInterpolation 函数,input 取值(0.0~1.0)
public class TestInterpolator implements TimeInterpolator {
    
    
    @Override
    public float getInterpolation(float input) {
    
    
        return (float) (Math.log10(1 + 9 * input));
    }
}

贝塞尔插值器学习资料
在这里插入图片描述

估值器(Evaluator)

插值器我们已经了解,是设置 变化速率的,那么估值器(Evaluator)是干什么的呢?看个正常效果的移动效果!!
在这里插入图片描述
再看看 增加了贝塞尔曲线公式的TypeEvaluator,看下效果,有抛物线的效果
在这里插入图片描述
从效果图,我们可以看出,估值器是改变了 具体数值;

用于控制动画如何从开始过渡到结束的,如:A(0,0) B(0,5)过两点之间的线可以是一条直线运动,也能是一条曲线,这个便由TypeEvaluator控制。

设置估值器 setEvaluator

类名 说明
IntEvaluator 这是用于计算 int 属性的值的默认评估程序。
FloatEvaluator 这是用于计算 float 属性的值的默认评估程序。
ArgbEvaluator 这是用于计算颜色属性的值(用十六进制值表示)的默认评估程序。
TypeEvaluator 此接口用于创建您自己的估值器。添加动画效果的对象属性不是 int、float 或颜色,那么就必须实现 TypeEvaluator 接口,才能指定如何计算对象属性添加动画效果之后的值。如果想以不同于默认行为的方式处理 int、float和颜色,还可以自定义 TypeEvaluator。

看看其中ArgbEvaluator的小栗子

ValueAnimator colorValueAnimator = ValueAnimator.ofObject(
	new ArgbEvaluator(), 0xFF00FF00, 0xFFFF0000, 0xFF0000FF);
colorValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
    
	@Override
	public void onAnimationUpdate(ValueAnimator animation) {
    
    
		colorView.setBackgroundColor((Integer)animation.getAnimatedValue());
	}
});
colorValueAnimator.setDuration(3000);
colorValueAnimator.start();

在这里插入图片描述

自定义TypeEvaluator 中 evaluate函数的几个参数

  • fraction 参数是插值器中的返回值,表示当前动画的数值进度,百分制的小数点(0.0~1.0)
  • startValue 开始值
  • endValue 结束值

前面效果的 自定义 的 贝塞尔曲线公式的TypeEvaluator
自定义估值器需要实现 TypeEvaluator的接口 与 复写evaluate 函数

public class BezierEvaluator implements TypeEvaluator<Point> {
    
    
	Point controlPoint;
	
    public BezierEvaluator(Point point) {
    
    
        controlPoint = point;
    }
    
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
    
    
        float x = (1 - fraction) * (1 - fraction) * startValue.x + 2 * fraction * (1 - fraction) * controlPoint.x + fraction * fraction * endValue.x;
        float y = (1 - fraction) * (1 - fraction) * startValue.y + 2 * fraction * (1 - fraction) * controlPoint.y + fraction * fraction * endValue.y;
        // 返回对象动画过渡的逻辑计算后的值
        return new Point((int)x, (int)y);
    }
}

抛物线的比较常见的效果可以参考 饿了么等应用的效果
在这里插入图片描述

小总结

估值器最要是协助插值器实现 非线性动画;插值器和估值器都是一个接口,且内部都只有一个方法,我们只要实现接口就可以了,就可以做出很多绚丽的动画。

一般来说,插值器使用系统的就足够了,估值器自定义的可能会多一些,另外就是如果要对其他类型(非Int丶float丶color)做动画,必须自定义类型估值算法。

感兴趣的小伙伴的具体的 查询 官方资料 以及 网上的相关资料

在 XML 中声明属性动画

XML与Animator对应的3个标签

  • <animatro />: 对应 ValueAnimator
<animator
	android:duration="int" # 动画执行时间
	android:startOffset="int" # 对应代码 startDelay,延迟多久开始动画
	android:valueFrom="float|int|color" # 起始值
	android:valueTo="float|int|color" # 结束值
	android:valueType="colorType|floatType|intType|pathType"
	android:repeatCount="int" # 对应代码 setRepeatCount
	android:repeatMode="restart(重新从头开始执行)|reverse(反方向执行)" # 对应代码 setRepeatMode
	android:interpolator="@android:interpolator/xxx" # 对应代码 setInterpolator,设置插值器
/>
  • <objectAnimator />: 对应 ObjectAnimator
<objectAnimator
	android:propertyName="string" # 属性名,比如 TranslationX,RotationX,Alpha 
    # 以下的属性与 animator 一致
    android:duration="int"
    android:startOffset="int"
    android:valueFrom="float|int|color"
    android:valueTo="float|int|color"
    android:valueType="colorType|floatType|intType|pathType"
    android:repeatCount="int|infinite"
    android:repeatMode="restart|reverse"
    android:interpolator="@android:interpolator/xxx"
/>
  • <propertyValuesHolder />: 对应 PropertyValuesHolder
<propertyValuesHolder
	android:propertyName="string"
	android:valueFrom="float|int|color"
	android:valueTo="float|int|color"
	android:valueType="colorType|floatType|intType|pathType"
/>
  • <set />: 对应 AnimatorSet
<set
	android:ordering="together(同时并行执行)|sequentially(顺序依次执行)"
/>

注意需要将XML的动画文件放在 animator 目录下
在这里插入图片描述
举个栗子

# 旋转 + 移动 + 透明 的动画效果
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    # 旋转 -720 ~ 0 度 X轴
    <objectAnimator
        android:duration="3500"
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="RotationX"
        android:valueFrom="-720"
        android:valueTo="0"
        android:valueType="floatType" />
    # 移动 0 ~ 500 X
    <objectAnimator
        android:duration="3500"
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="TranslationX"
        android:valueFrom="0"
        android:valueTo="500"
        android:valueType="floatType" />
    # 透明 0.1~1.0 
    <objectAnimator
        android:duration="3500"
        android:interpolator="@android:anim/bounce_interpolator"
        android:propertyName="Alpha"
        android:valueFrom="0.1"
        android:valueTo="1.0"
        android:valueType="floatType" />
</set>        

看最终效果
在这里插入图片描述

场景小剧场

桌面的 图标 放大效果
在这里插入图片描述
唱盘机的旋转
在这里插入图片描述
歌词滚动
在这里插入图片描述
菜单
在这里插入图片描述
音乐控制器升级的手势动画效果
在这里插入图片描述

存在的问题

1. 动画再执行,Activity或者Fragment,其它的界面退出了,只能在每个生命周期结束的时候进行清除,很繁琐!!
2. AnimatorSet无法实现无限循环动画.(没有 setRepeatCount 函数). 需要给每个 Animator 动画去设置 setRepeatCount,很麻烦
3. 无法统一去设置插值器,只能统一写一个地方,然后调用
4. 弄一些复杂的动画,代码写了N多!!!

其它解决方案:
使用 我们团队之前写的 OpenAnim,能很方便的完成以上这些事情,我们团队现在已经投入使用,并且还支持生命周期的监听,后续还将支持其它功能(比如 转场,滚动优化… …)

OpenAnim.with(this)
		.into(view)
      	.together(
       		new TranslationXAnimator(500),
       		new TranslationYAnimator(100),
       		new RotationXAnimator(0, 360),
        	new RotationYAnimator(0, 360))
        .duration(3000)
        .interpolate(new LinearInterpolator())
        .repeatCount(ValueAnimator.INFINITE)
		.start();
# 配置全局配置
<meta-data
	android:name="AnimModule"
    android:value="com.open.tvwidget.TestAnimModule" />
    
# 代码    
public class TestAnimModule implements AnimModule {
    @Override
    public void applyOptions(Context context, AnimConfigBuilder builder) {
       // 设置N多种配置(时间,插值器,估值器等等)
		builder.duration(1000)
			   .typeEvaluator(new BounceEaseOut(500))
               .interpolate(new DecelerateInterpolator());
    }

}

在这里插入图片描述

参考资料

属性动画文档地址
属性动画XML
Android 动画 Animator 家族使用指南
估值器详解
属性动画高阶用法


Android动画了解—视图动画 <=上个章节 下个章节=> Android动画了解—转场/过渡(Transition) 动画

猜你喜欢

转载自blog.csdn.net/qw85525006/article/details/104911456