属性动画
在前面学习了安卓的帧动画和补间动画,其实那两种动画都属于一类,并没有对VIew的属性进行了改变,就是靠视觉效果来展现动画的,所以就出现了属性动画
为啥要有属性动画
1逐帧动画和补间动画只能作用于视图上,只可以对一个Button,TextView,,,或者继承View的组件进行操作,但无法对非view的对象进行操作
2没有改变view的属性,只是改变了视觉效果
3动画效果单一
工作原理:在一定时间内,不断对值进行变化,然后将值赋值给对象的属性//对象的任意属性
所以这里面有两个关键类,还是两种实现方式,一种java方式,一直xml方式,但这里推荐java方式,因为很多属性和起始值都不能在xml里面获取,需要在java里面获取
//xml模式 采用animator标签
ValueAnimator 手动赋值
ObjectAnimator 自动赋值
ValueAnimator类
其实这个原理也蛮简单,
设定好对象属性初始值和结束值,
通过插值器和估值器来设定变化的逻辑规律,根据规律不断改变值,然后每当值改变一遍,就手动赋值给对象属性值一次
不断刷新视图 绘制视图
如果初始值等于结束值 就结束了
从上面原理可以看出:ValueAnimator类中有3个重要方法:
ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)
ValueAnimator.ofInt(int values)
作用:将初始值 以整型数值的形式 过渡到结束值
下面是个例子 按钮测试一的宽度变化
private Button mButton;
private ValueAnimator valueAnimator;//整形估值器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//创建动画对象
mButton = (Button)findViewById(R.id.btn_play);
//1设置属性数值的初始值和结束值
valueAnimator = ValueAnimator.ofInt(mButton.getLayoutParams().width,500);
//初始值 = 当前按钮的宽度
//结束值 = 500
//ValueAnimator.ofInt()里面内置了整形估值器,默认看如何变化
//2设置动画的各种属性
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(5);
//3将属性数值手动赋值给对象的属性 这里是将值付给按钮的宽度
//更新监听器,数值每次变化都会调用这个方法
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (int) animation.getAnimatedValue();
//获取每次变化的值
mButton.getLayoutParams().width = currentValue;
//每次赋值
mButton.requestLayout();
//4刷新视图。重新绘制
}
});
//5启动动画
valueAnimator.start();
}
过程代码上都有
1创建动画对象
2设置属性数值的初始值和结束值
3设置动画的各种属性
4使用监听器,然后只要变化就给属性赋值
5刷新视图
6启动动画
ValueAnimator.oFloat(float values)
作用:将初始值 以浮点型数值的形式 过渡到结束值
ValueAnimator.ofInt()与ValueAnimator.oFloat()仅仅只是在估值器上的区别:(即如何从初始值 过渡 到结束值)
ValueAnimator.oFloat()采用默认的浮点型估值器 (FloatEvaluator)
ValueAnimator.ofInt()采用默认的整型估值器(IntEvaluator)
过程和上面的一样 不再讲了
ValueAnimator.ofObject()
作用:将初始值 以对象的形式 过渡到结束值
这个和上面两个还不太一样,这个初始值是初始动画的对象,结束值是结束动画的对象
// 创建初始动画时的对象 & 结束动画时的对象
myObject object1 = new myObject();
myObject object2 = new myObject();
ValueAnimator anim = ValueAnimator.ofObject(new myObjectEvaluator(), object1, object2);
// 创建动画对象 & 设置参数
// 参数说明
// 参数1:自定义的估值器对象(TypeEvaluator 类型参数) - 下面会详细介绍
// 参数2:初始动画的对象
// 参数3:结束动画的对象
anim.setDuration(5000);
anim.start();
估值器(TypeEvaluator)
作用:设置动画 如何从初始值 过渡到 结束值 的逻辑
插值器(Interpolator)决定 值 的变化模式(匀速、加速blabla)
估值器(TypeEvaluator)决定 值 的具体变化数值
先看下估值器其实是个接口
public interface TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue)
参数:fraction 动画完成度
startValue 动画初始值
endValue 动画结束值
目的:要返回当前完成度的值
计算方式:目前值 = 初值+完成度*(结束值-初始值)
下面有个例子 自定义了一个小球对象 成员变量是坐标x和y值 然后自定义插值器
public class PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//讲动画的初始值和结束值强制转换为Point对象
Point startPoint = (Point)startValue;
Point endPoint = (Point)endValue;
//根据fraction来计算当前的x和y的值
float x = startPoint.getX()+fraction*(endPoint.getX()-startPoint.getX());
float y = startPoint.getY()+fraction*(endPoint.getY()-startPoint.getY());
//将算好的坐标封装好给一个新的Point对象并返回
Point point = new Point(x,y);
return point;
}
}
ObjectAnimator类
直接对对象的属性值进行改变操作,从而实现动画效果
如直接改变 View的 alpha 属性 从而实现透明度的动画效果
继承自ValueAnimator类,即底层的动画实现机制是基ValueAnimator类
本质原理: 通过不断控制 值 的变化,再不断 自动 赋给对象的属性,从而实现动画效果
从上面的工作原理可以看出:ObjectAnimator与 ValueAnimator类的区别:
ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;
ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;
这个用java里面设置特别快我们使用了属性动画最基本的四种动画效果:透明度、平移、旋转 & 缩放
即在ObjectAnimator.ofFloat()的第二个参数String property传入alpha、rotation、translationX 和 scaleY 等blabla
自动赋给对象的属性的本质是调用该对象属性的set() & get()方法进行赋值
所以,ObjectAnimator.ofFloat(Object object, String property, float ….values)的第二个参数传入值的作用是
让ObjectAnimator类根据传入的属性名 去寻找 该对象对应属性名的 set() & get()方法
看下效果图
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
button1 = (Button)findViewById(R.id.btn_ow1);
button2 = (Button)findViewById(R.id.btn_ow2);
button3 = (Button)findViewById(R.id.btn_ow3);
button4 = (Button)findViewById(R.id.btn_ow4);
button5 = (Button)findViewById(R.id.btn_ow5);
button6 = (Button)findViewById(R.id.btn_ow6);
//第一个透明度
ObjectAnimator animator = ObjectAnimator.ofFloat(button1,"alpha",1f,0f,1f);
//第一个参数是动画的对象 第二个是操作的对象的属性 第三个是初始值 最后一个是结束的值
animator.setDuration(5000);
animator.setRepeatCount(-1);
animator.start();
//第二个旋转
ObjectAnimator animator1 = ObjectAnimator.ofFloat(button2,"rotation",0f,360f);
animator1.setDuration(5000);
animator1.setRepeatCount(-1);
animator1.start();
//第三个平移
float curTranslationX = button3.getTranslationX();
float curTranslationX1 = button6.getTranslationX();
//获取当前位置
ObjectAnimator animator2 = ObjectAnimator.ofFloat(button3,"translationX",curTranslationX,300,curTranslationX);
animator2.setDuration(5000);
animator2.setRepeatCount(-1);
animator2.start();
//第四个缩放
ObjectAnimator animator3 = ObjectAnimator.ofFloat(button4,"scaleX",1f,3f,1f);
animator3.setDuration(5000);
animator3.setRepeatCount(-1);
animator3.start();
//第五个 组合动画的java方式
// //组合动画
// ObjectAnimator translation = ObjectAnimator.ofFloat(button6,"translationX",curTranslationX1,300,curTranslationX1);
// ObjectAnimator rotate = ObjectAnimator.ofFloat(button6,"rotation",0f,365f);
// ObjectAnimator alpha = ObjectAnimator.ofFloat(button6,"alpha",1f,0f,1f);
// //创建组合动画的对象
// AnimatorSet animatorSet = new AnimatorSet();
// //根据组合动画对象组合
// animatorSet.play(translation).with(rotate).before(alpha);
// animatorSet.setDuration(5000);
//
// animatorSet.start();
//第五个 组合动画的xml方式
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.set2_animation);
animatorSet.setTarget(button6);
animatorSet.start();
button5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent2 = new Intent(Main3Activity.this,Main4Activity.class);
startActivity(intent2);
}
});
}
组合模式的xml 在res/animator 里面建立的 跟标签是set
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<set
android:ordering="together">
<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType"/>
</set>
<set
android:ordering="sequentially">
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"/>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
</set>
</set>
实现步骤:
也是两种方式 一种java一种xml方式
java方式:
1创建ObjectAnimator对象
ObjectAnimator animator = ObjectAnimator.ofFloat(button1,”alpha”,1f,0f,1f);
//第一个参数是动画的对象 第二个是操作的对象的属性 第三个是初始值 最后一个是结束的值
2设置动画的其他属性 比如时间啊 循环次数
3启动动画
xml方式
1.在xml 在res/animator 里面建立的xml文件 如果是组合动画 跟标签是set
2在java代码里面创建对象//下面是组合属性动画的对象AnimatorSet
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.set2_animation);
//参数 上下文,xml
animatorSet.setTarget(button6);
//绑定控件
animatorSet.start();
//启动动画
总结
属性动画也就是这些内容,可能自定义插值器那块有点难,其他的都还行,蛮有意思的嘻嘻