属性动画
介绍
属性动画本质就是动态改变View的属性。
PS:属性动画不仅可以改变View的属性。只要是一个对象的属性,有set/get方法,就可以动态的去变化。
先上全部代码:
private void objectAnimationFromXML() {
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.translationx);
animator.setTarget(showView);
animator.start();
}
private void objectAnimationFromJavaCode() {
//将view的tranlationX属性,在2000ms从0变化到100
ObjectAnimator.ofFloat(showView, "translationX", 0, 100)
.setDuration(2000)
.start();
}
private void animatorSet() {
ObjectAnimator translationX = ObjectAnimator.ofFloat(showView, "translationX", 0, 100)
.setDuration(2000);
ObjectAnimator translationY = ObjectAnimator.ofFloat(showView, "translationY", 0, 100)
.setDuration(2000);
ObjectAnimator alpha = ObjectAnimator.ofFloat(showView, "alpha", 1.0f, 0.5f)
.setDuration(2000);
ObjectAnimator scale = ObjectAnimator.ofFloat(showView, "scaleX", 1.0f, 0.5f)
.setDuration(2000);
ObjectAnimator rotate = ObjectAnimator.ofFloat(showView, "rotation", 0, 180)
.setDuration(2000);
//以下动画播放顺序,scale->(translationY,alpha)->translationX
AnimatorSet set = new AnimatorSet();
set.play(translationY).with(alpha).before(translationX).after(scale);
//动画5在1000ms后播放。
set.play(rotate).after(1000);
set.setDuration(2000);
set.start();
}
private void valueAnimator() {
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
if (value < 50) {
showView.setTranslationX(value);
} else {
showView.setTranslationY(value);
}
}
});
animator.setDuration(2000);
animator.start();
}
private void typeEvaluator() {
showView.setClipToOutline(true);
Circle first = new Circle();
first.setR(0);
Circle end = new Circle();
end.setR(showView.getHeight() / 2);
ValueAnimator animator = ObjectAnimator.ofObject(new CircleEvaluator(), first, end);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final Circle circle = (Circle) animation.getAnimatedValue();
showView.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), circle.getR());
}
});
}
});
animator.start();
}
private void interpolator() {
ObjectAnimator translationX =
ObjectAnimator.ofFloat(showView, "translationX", 0, 500)
.setDuration(2000);
translationX.setInterpolator(new ReverseInterpolator());
translationX.start();
}
private void viewPropertyAnimator() {
//简单的x轴y轴平移到100的位置,横向纵向放大到2倍,旋转180度,播放时长1s
showView.animate().x(100).y(100).scaleX(2).scaleY(2).rotation(180).setDuration(1000);
}
ObjectAnimator
一般情况下,ObjectAnimator类是能属性动画写法简化的一个类。
ObjectAnimator方法有ofInt、ofFloat等方法,传入一个对象,一个对象的属性,一个数值变化范围(如0-100-1000),就会主动调用Object的Set方法不断去设置属性,并触发重绘。
XML动画制作写法:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="100"
android:valueType="floatType">
</objectAnimator>
JAVA引用XML文件方法
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.tranlation_animator);
animator.setTarget(view);
animator.start();
JAVA代码动画制作写法:
//将view的tranlationX属性,在2000ms从0变化到100
ObjectAnimator.ofFloat(view,"translationX",0,100)
.setDuration(2000)
.start();
AnimatorSet
动画集,关联多个Animator动画。
//以下动画播放顺序,1->(2,3)->4
AnimatorSet set = new AnimatorSet();
set.play(2).with(3).before(4).after(1);
//动画5在1000ms后播放。
set.play(5).after(1000);
set.setDuration(2000);
set.start();
ValueAnimator
ValueAnimator是ObjectAnimator的父类,它相当于只提供了一个数据变化的功能。需要自己去实现数据变化时,具体要执行的操作。大多数时候,我们自定义一些特殊的动画的时候,都是使用ValueAnimator类。
常见用法
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float)animation.getAnimatedValue();
//数值更新时进行的操作。
}
});
animator.setDuration(2000);
ps:数值更新时应当使用postInvalidateOnAnimation来优化,postInvalidateOnAnimation 依赖上一帧动画的的执行时间,因为动画的刷新是存在一个频率的,直到下一帧动画的时间才会真正执行刷新操作。
动画监听
AnimatorListener,以上几种类型的动画都支持设置此监听
animator.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) {
//动画重复播放监听
}
});
同时为了避免重写四个方法的繁琐,提供了AnimatorListenerAdapter类,只需要重写自己想要监听的方法即可。
TypeEvaluator
估值器:简单来说,就是告诉动画系统如何从初始值过渡到结束值。
以常见的ObjectAnimator.ofFloat()方法为例,
FloatEvaluator源码:
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
可以看出来,其实就是初始值加上变化值。
看起来是不是很简单,但是就这玩意儿我们用好了,就可以实现一系列花里胡哨的动画了,什么圆形变成心形啦,什么心形弹弹弹啦。自定义的话,其实就是实现TypeEvaluator接口的evaluate方法啦~
举个简单的栗子吧:
public class Circle {
private int r;
public int getR() {
return r;
}
public void setR(int r) {
this.r = r;
}
}
public class CircleEvaluator implements TypeEvaluator<Circle> {
@Override
public Circle evaluate(float fraction, Circle startValue, Circle endValue) {
if (startValue == null || endValue == null) {
return startValue;
}
int startR = startValue.getR();
int endR = endValue.getR();
int nowR = startR + (int) (fraction * (endR - startR));
Circle nowCircle = new Circle();
nowCircle.setR(nowR);
return nowCircle;
}
}
应该很明显就能看出来,这就是个简单的圆半径变化的估值器。大家可以想象一下利用这个玩意儿可以实现什么样的动画啦!
Interpolator
插值器:它的作用概括来说就是控制动画变化的速度。可以看到TypeEvaluator的接口evaluate方法中有一个fraction参数,这个参数的值其实就是根据Interpolator计算得出的。
我们平常使用属性动画时,系统默认的Interpolator其实就是一个先加速后减速的Interpolator,对应的实现类就是AccelerateDecelerateInterpolator。
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
}
}
其中重点是getInterpolation()方法,这个方法就是最终提供给TypeEvaluator使用的fraction。
再举一个简单的栗子:
public class ReverseInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return 1 - input;
}
}
这就简单的实现倒序的变化啦!是不是很easy!
再推荐大家一个变化函数直观看效果的网站(里面也有很多已经实现好的函数,用起来贼得劲!):
http://inloop.github.io/interpolator/
下面这个网站也包含了很多函数,大家也可以参考一下!
https://easings.net/cn#
ViewPropertyAnimator
专门提供给View的快捷的Animator操作。拥有更好的性能,只执行一次刷新操作就能将所有动画绘制一次,而我们平常使用的Animator每一个都需要绘制一次。
//简单的x轴y轴平移到100的位置,横向纵向放大到2倍,旋转180度,播放时长1s
view.animate().x(100).y(100).scaleX(2).scaleY(2).rotation(180).setDuration(1000);
ViewPropertyAnimator支持的方法还是挺多的,能满足咱们大多数的需求。而且调用真的是很方便!