本文共 12582 字,大约阅读时间需要 41 分钟。
见名知义,属性动画通过控制对象的属性,(修改控件的属性值
)来实现动画效果。属性动画是在Android3.0之后引进的,它非常的强大,可以比较简单的实现许多视图动画做不到的事情。
在使用属性动画之前先来看几个常用的View属性成员:
translationX,translationY,translationZ
:控制View的位置,值是相对于View容器左上角坐标的偏移。rotationX,rotationY
:控制相对于轴心旋转。(0f-> 360f
)0f-> 1f
)scaleX
,垂直缩放scaleY
ValueAnimator 是ObjectAnimato的父类:
ValueAnimator ofInt (int... values)
:返回一个int型变化的ValueAnimator。ValueAnimator ofFloat (float... values)
:返回一个float型变化的ValueAnimator。ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):
返回一个object型变化的ValueAnimator。ValueAnimator ofArgb (int... values)
:返回一个颜色值变化的ValueAnimator,API LEVEL 21引入。mLinearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ObjectAnimator animator; if(!flag){ animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,-70f); flag = true; }else { animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,0f); //animator.setInterpolator(new OvershootInterpolator()); flag = false; } animator.start(); } });
通过ObjectAnimator
的工厂方法ofFloat
我们得到一个ObjectAnimator
对象,并通过该对象的start()
方法,开启动画效果。
ofFloat()
方法的第一个参数为要实现动画效果的View,例如这里整体效果的LinearLayout
;第二个参数为属性名,也就是前面所说的:translationX,translationY,alpha,rotation,scaleX,scaleY
等,这里要实现的是水平平移效果,所以我们采用了translationX
;第三参数为可变长参数,第一个值为动画开始的位置,第二个值为结束值得位置
,如果数组大于3位数,那么前者将是后者的起始位置。 translationX
和translationY
这里涉及到的位移都是相对自身位置而言。 例如: View在点A(x,y)要移动到点B(x1,y1),那么ofFloat()方法的可变长参数,第一个值应该0f,第二个值应该x1-x。 XML布局实现:
在res/animator文件夹下,创建animator_translation.xml文件,内容如下:ObjectAnimator animator = AnimatorInflater.loadAnimator(this,R.animator.animator_translation); animator.setTarget(mLinearLayout); animator.start();
mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView, "alpha",1f,0f,1f); objectAnimator.setDuration(3000); objectAnimator.start(); } });
//第一个参数是控件,第二个是选择什么动画属性 例如 scaleX(x轴缩放),scaleY ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView, "scaleX",1f,2f,3f,2f,1f); objectAnimator.setDuration(3000);//动画持续时间 objectAnimator.setRepeatCount(2);//动画重复次数 objectAnimator.setRepeatMode(ValueAnimator.REVERSE);//动画持续模式 上一次效果反着来 objectAnimator.start();
//ofFloat()方法的可变长参数,如果后者的值大于前者, // 那么顺时针旋转,小于前者,则逆时针旋转。 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mTextView, "rotation",0f,180f,0f,-360f,0f); objectAnimator.setDuration(3000);//动画持续时间 objectAnimator.start();
代码直接利用 AnimatorSet() 如果是XML定义AnimatorSet 利用AnimatorInflater.loadAnimator()加载(使用较少)
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,R.animator.property_animator);set.setTarget(mTextView);set.start();
AnimatorSet可以作用于ObjectAnimator和ValueAnimator,但通常ObjectAnimator用的比较多。
AnimatorSet的相关函数:
setInterpolator (TimeInterpolator interpolator)
,设置之后内部子动画的插值器都是这个setTarget(Object target)
,设置之后所有内部子动画都作用于相同的target目标对象setStartDelay(long startDelay)
,它不会覆盖子动画开始延迟,只对AnimatorSet的开始时间起作用,所以它会延后AnimatorSet激活整体动画的开始时间cancle()
取消动画,会取消AnimatorSet中的所有子动画。end()
结束动画,会结束AnimatorSet中的所有子动画。getChildAnimations()
获取所有受AnimatorSet控制的动画isStarted()
,AnimationSet动画是否开始了,true开始isRunning()
,AnimationSet开始之后(isStarted = true),内部是否有子动画正在执行,有动画执行返回truepause()
暂停动画,resume()
恢复暂停的动画play(Animator anim)
获取Builder对象函数 playTogether
和playSequentially
的区别:
animatorSet.playTogether():
多个动画同时执行,可以是对一个对象执行的多个动画,也可以是对多个对象的多个动画。playTogether(Collection<Animator> items)
//利用集合添加动画playTogether(Animator... items)
//利用可变参数添加动画
ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f); ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 50); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4); animatorSet.setDuration(3000); animatorSet.start();
效果和animatorSet.playTogether()差不多 PropertyValuesHolder holder1=PropertyValuesHolder.ofFloat("rotation",0f,360f,0f); PropertyValuesHolder holder2=PropertyValuesHolder.ofFloat("translationX",0f,600f); PropertyValuesHolder holder3=PropertyValuesHolder.ofFloat("alpha",1f,0f,1f); ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(sun,holder1,holder2,holder3); objectAnimator.setDuration(3000); objectAnimator.setInterpolator(new OvershootInterpolator());//插值器 objectAnimator.start();
如果多个动画同时对控件的同一个属性进行操作,会按照playTogether添加的最后一个动画覆盖前面操作相同属性的动画,也可能没有覆盖,但确实是最后一个添加的动画起了作用。
playSequentially
顺序播放动画:playSequentially(List<Animator> items)
playSequentially(Animator... items)
playSequentially
是一个动画执行完后执行下一个动画,但如果前一个动画是无限循环,下一个动画永远不会执行。
ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(mTextView, "translationY", 200, 450); ObjectAnimator objectAnimator6 = ObjectAnimator.ofFloat(mTextView, "translationY", 300, 600); ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f); ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250); AnimatorSet animatorSet = new AnimatorSet(); //按顺序执行动画 animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6); animatorSet.setDuration(5000); animatorSet.start();
//实现动画无限循环 objectAnimator1.setRepeatCount(-1); animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
Builder play(Animator anim);生成builder对象,Builder能够控制动画的执行顺序和相互之间的依赖。
Builder的函数:
public Builder with(Animator anim)
和前面动画一起执行public Builder before(Animator anim)
执行前面的动画后再执行该动画public Builder after(Animator anim)
先执行这个动画再执行前面动画public Builder after(long delay)
延迟n毫秒之后执行动画//按函数性质执行动画 animatorSet.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3); animatorSet.setDuration(5000); animatorSet.start(); /* * 链式调用动画执行顺序总结如下: Builder链式调用中会先执行after函数中的动画(有多个同时执行), * 然后执行play和with函数(有多个同时执行)中的动画, * 最后执行before函数中的动画(有多个同时执行) * */
动画监听animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { }});//需要api19animatorSet.addPauseListener(new Animator.AnimatorPauseListener() { @Override public void onAnimationPause(Animator animation) { } @Override public void onAnimationResume(Animator animation) { }});
//ViewPropertyAnimator 动画,只是针对View对象的特定属性同时播放动画 /* * 支持属性: translationX、translationY、translationZ x、y、z alpha scaleX、scaleY * * */ mTextView.animate().translationX(100f).translationY(100f).translationZ(20f). setInterpolator(new OvershootInterpolator()).start();
//ViewPropertyAnimator 动画,只是针对View对象的特定属性同时播放动画 ViewPropertyAnimator viewPropertyAnimator = mTextView.animate(); viewPropertyAnimator.setDuration(2000); viewPropertyAnimator.translationX(100f);//点击一次向右偏移,之后点击无效果(一次性) //viewPropertyAnimator.translationXBy(100f);//每次点击都会向右偏移,重复利用 viewPropertyAnimator.start();
插值器:根据时间流逝的百分比计算出当前属性值改变的百分比。
正常情况下,默认的插值器已经够用,如果自己数学厉害,想显摆一下,也是通过实现TimeInterpolator接口的getInterpolation()自定义
的。 /** * A time interpolator defines the rate of change of an animation. This allows animations * to have non-linear motion, such as acceleration and deceleration. */public interface TimeInterpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input);}
估值器:根据当前属性改变的百分比来计算改变后的属性值,移动的位置;
自定义估值器:
//自定义估值器,重写计算规则,多利用数学公式 class BallDownEvaluator implements TypeEvaluator{ /** * @param fraction 动画执行了的百分比, * * @param startValue 点的起始值 * * @param endValue 点的最终值 * @return * */ @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { //以后可以利用估值器实现更多的曲线动画,比如贝塞尔、正弦余弦动画等。 //抛物线方程式 s=1/2*g*t*t //定义初速度150,加速g=9.8,时间t=5s,就是动画设置的执行时间 float time = 5* fraction* 1.0f; PointF pointF = new PointF(); pointF.x = 150 * time; pointF.y = 0.5f * 98.0f *time *time; return pointF; } }
mTextView.setOnClickListener(new View.OnClickListener() { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onClick(View view) { //ValueAnimator 是 ObjectAnimator 的父类 //太阳下山抛物线 ObjectAnimator objectAnimator = new ObjectAnimator(); BallDownEvaluator ball = new BallDownEvaluator(); objectAnimator.setDuration(5000); //1.先设置value 位置(0,0) objectAnimator.setObjectValues(new PointF(0,0)); //2.再设置估值器 objectAnimator.setEvaluator(ball); objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { PointF pointF = (PointF) valueAnimator.getAnimatedValue(); //通过不断的改变view(sun)的坐标来实现抛物线动画 sun.setX(pointF.x); sun.setY(pointF.y); } }); objectAnimator.start(); } });
假如觉得自定义自定义插值器或估值器有难度,也可以使用关键帧Keyframe对象
来实现。Keyframe
让我们可以指定某个属性百分比时对象的属性值。
Keyframe start = Keyframe.ofFloat(0f,0f); Keyframe middle1 = Keyframe.ofFloat(0.3f,300f); Keyframe middle2 = Keyframe.ofFloat(0.7f,600f); Keyframe end = Keyframe.ofFloat(1f,900f); PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX", start,middle1,middle2,end); ObjectAnimator.ofPropertyValuesHolder(sun,holder).setDuration(3000).start();
链接:
链接:新小梦 https://juejin.cn/post/6846687601118691341转载地址:http://phrii.baihongyu.com/