1. 前言
这是动画的第三篇属性动画,属性动画是android动画里面用的最多的, 也是最重要的。android中三种动画的使用文章以下:java
2. 介绍
3. 使用
3.1 ValueAnimator使用
先来一张动画效果图android
3.1.1 ValueAnimator 介绍
3.1.2 ofInt、ofFloat、ofArgb
经过调用ValueAnimator.ofInt这个方法, 咱们就能构建一个整型的ValueAnimator,以下:git
private void valueAnimatorOfInt() {
//获取到屏幕宽度
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
//起始值为btn最开始的坐标的x位置, 结束值为 屏幕的最右边,
ValueAnimator valueAnimator = ValueAnimator.ofInt((int) btnOfInt.getTranslationX(), widthPixels);
valueAnimator.setDuration(2000);
valueAnimator.setRepeatCount(2);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setStartDelay(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int currentValue = (int) valueAnimator.getAnimatedValue();
btnOfInt.setTranslationX(currentValue);
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
复制代码
解释:github
使用十分简单,ValueAnimator.ofFloat,ValueAnimator.ofArgb 都是同理,传入开始值和结束值, 而后监听数值的变化, 设置给你要进行动画的view。 下面定义了两个方法,是对ofFloat,ofArgb的使用:canvas
private void valueAnimatorOfFloat() {
//获取到屏幕宽度
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
//起始值为btn最开始的宽度, 结束值为 屏幕的宽度。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(btnofFloatWidth,widthPixels);
valueAnimator.setDuration(2000);
// valueAnimator.setRepeatCount(2);
// valueAnimator.setRepeatMode(ValueAnimator.RESTART);
// valueAnimator.setStartDelay(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float currentValue = (float) valueAnimator.getAnimatedValue();
btnOfFloat.getLayoutParams().width = (int) currentValue;
//从新绘制
btnOfFloat.requestLayout();
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
private void valueOfRGB(){
ValueAnimator valueAnimator = ValueAnimator.ofArgb(Color.BLUE, Color.RED);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int currentValue = (int) valueAnimator.getAnimatedValue();
btnOfRgb.setBackgroundColor(currentValue);
System.out.println("current value:" + currentValue);
}
});
valueAnimator.start();
}
复制代码
3.1.3 ValueAnimator.ofObject
在介绍中说过, 属性动画能够做用在任意对象。 好比我有一个Point类,类中有x,y两个属性用来表示坐标。 经过Point建立两个对象,一个pointA,PointB。如何从pointA变化到pointB呢?bash
public class MyView extends View {
private float RADIUS = 50f;
private Point currentPoint;
private Paint mPaint ;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
currentPoint = new Point(RADIUS,RADIUS);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas);
}
private void drawCircle(Canvas canvas){
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x,y,RADIUS,mPaint);
}
public void startAnimation (){
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),startPoint,endPoint);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Point point = (Point)valueAnimator.getAnimatedValue();
currentPoint = point;
invalidate();
System.out.println("current point,x:"+currentPoint.getX()+"y:"+currentPoint.getY());
}
});
valueAnimator.start();
}
}
复制代码
自定义了一个view画一个圆。startAnimation方法可使这个圆从startPoint移动到endPoint。dom
解释:ide
ValueAnimator.ofObject: 经过ofObject建立一个动画对象, 传入估值器、开始对象和结束对象。post
估值器是个什么东西?
估值器就是用来描述动画逻辑的,说白了就是计算在对应的时间点上, 当前的值是多少。 以前的ofInt、ofFloat、ofArgb 这些, 系统都帮咱们写好了,计算好了。 可是若是是从一个任意对象变化到另外一个对象。 就须要咱们本身写估值器了。动画
/**
* point 估值器
*/
public class PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
}
复制代码
实现TypeEvaluator接口就好了, 接口会传当前动画进度、开始对象和结束对象进来。 你只须要根据这三个东西来计算出当前动画进度的对象并返回就能够了。
3.1.4 PropertyValuesHolder
上面都是对一个属性变化进行动画, 若是是多个呢,好比我要改一个按钮的宽和高。 那就要用到PropertyValuesHolder。
private void valueOfPropertyValues(){
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
int heightPixels = displayMetrics.heightPixels;
PropertyValuesHolder holder1 = PropertyValuesHolder.ofInt("width", btnWidth, widthPixels);
PropertyValuesHolder holder2 =PropertyValuesHolder.ofInt("height",btnHeight,heightPixels-btnOfValuesProperty.getTop());
ValueAnimator valueAnimator = ValueAnimator.ofPropertyValuesHolder(holder1, holder2);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int width = (int) valueAnimator.getAnimatedValue("width");
int height = (int) valueAnimator.getAnimatedValue("height");
btnOfValuesProperty.getLayoutParams().width = width;
btnOfValuesProperty.getLayoutParams().height = height;
btnOfValuesProperty.requestLayout();
System.out.println("width:"+width+"height:"+height);
}
});
valueAnimator.start();
}
复制代码
解释:
PropertyValuesHolder.ofInt: 和刚刚的ValueAnimator.ofInt 同样, 都是传入一个开始值和结束值。建立出来一个要变化的属性对象。
ValueAnimator.ofPropertyValuesHolder: 把建立的多个要变化的属性对象传进来,构建出一个动画对象。
valueAnimator.getAnimatedValue: 经过属性名, 获取到属性的当前值。拿到多个属性值后, 咱们就能够来从新设置按钮的宽高造成动画啦。
3.1.4 ValueAnimator使用总结
咱们传入一个开始值和结束值给到ValueAnimator, 它会帮咱们计算出在当前时间,这个值是多少。 咱们经过监听获取到这个值,从新设置给view等对象,让view重绘。这就是ValueAnimator作动画的原理。
3.2 ObjectAnimator使用
上面说的ValueAnimator咱们是经过监听值的变化来给view设置属性,从新绘制,完成动画。 那么ObjectAnimator就是咱们把属性名给它,让他本身来根据属性值的变化完成动画。
3.2.1 translate、rotate、scale、alpha
好比咱们要经过ObjectAnimator来改变view的属性,让view平移、选择、缩放、透明:
private void translate() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnTranslate, "translationX", 0, 500, 200);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void rotate() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnRotate, "rotation", 0, 200, 300);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void scale() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnScale, "ScaleX", 0f, 0.5f, 1.1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
private void alpha() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btnAlpha, "Alpha", 0, 0.5f, 1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
}
复制代码
解释:
3.2.2 自定义属性
上面那些是view本地有自带的setTranslationX、setRotation等方法,才能够经过translationX、rotataion这些属性来完成动画。 若是咱们自定义的view,要变化其余属性呢,好比一个进度条, 经过变化进度属性值来完成进度的动画。那就须要咱们本身定义属性和属性对应的setter方法,并在setter方法中,重绘view。
public class ProgressView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float progress = 0;
private float RADIUS = 80;
public ProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public float getProgress() {
return progress;
}
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float centerX = getWidth()/2;
float centerY = getHeight()/2;
mPaint.setColor(Color.RED);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(25);
mPaint.setStyle(Paint.Style.STROKE);
RectF rectF = new RectF(centerX - RADIUS, centerY - RADIUS, centerX + RADIUS, centerY + RADIUS);
canvas.drawArc(rectF,0,3.6f*progress,false,mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText((int) progress + "%", centerX, centerY - (mPaint.ascent() + mPaint.descent()) / 2, mPaint);
}
}
复制代码
private void custom() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(progressView, "progress", 0, 90);
objectAnimator.setDuration(5000);
objectAnimator.setInterpolator(new FastOutSlowInInterpolator());
objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
objectAnimator.addListener(new AnimatorListenerAdapter() {
// @Override
// public void onAnimationStart(Animator animation) {
// super.onAnimationStart(animation);
// }
});
}
复制代码
这样咱们就能够对咱们自定义view中的属性变化并完成动画了。
3.2.2 指定动画的关键帧
这里的关键帧就是用来指定,在某一帧的时候的属性。 好比动画到一半时候的那一帧, 我要把属性设置成什么什么。下面例子仍是用上面那个进度条, 当动画到一半的时候,把进度设置成100。
private void keyFrame() {
//设置关键帧, 第一个参数是 完成度, 第二个参数是 属性值, 好比当完成度一半的时候(0.5),属性值(progress)给100;
Keyframe keyframe = Keyframe.ofFloat(0, 0);
Keyframe keyframe1 = Keyframe.ofFloat(0.5f, 100);
Keyframe keyframe2 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe, keyframe1, keyframe2);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(progressView, holder);
objectAnimator.setDuration(5000);
objectAnimator.start();
}
复制代码
解释:
3.3 ViewPropertyAnimator使用
ViewPropertyAnimator, 是直接经过view的animate来对view的一些自带属性进行动画。 animate返回的对象就是ViewPropertyAnimator类型。
private void viewProperty(){
btnViewProperty.animate().alpha(0).setDuration(2000).rotation(360).translationX(300);
}
复制代码
3.4 组合动画
不少时候, 单个动画知足不了需求。 须要将多个动画变成一连串的组合动画。 好比讲移动、旋转、透明组合起来, 一块儿或者前后完成动画。
private void animatorSet() {
// AnimatorSet.playTogether(Animator... anim) : 将动画组合一块儿执行
// AnimatorSet.playSequentially(Animator... anim) : 将动画组合有序执行
// AnimatorSet.play(Animator anim) :播放当前动画
// AnimatorSet.after(long delay) :将现有动画延迟x毫秒后执行
// AnimatorSet.with(Animator anim) :将现有动画和传入的动画同时执行
// AnimatorSet.after(Animator anim) :将现有动画插入到传入的动画以后执行
// AnimatorSet.before(Animator anim) : 将现有动画插入到传入的动画以前执行
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
int widthPixels = displayMetrics.widthPixels;
ObjectAnimator translationX = ObjectAnimator.ofFloat(btnSet, "translationX", 0, widthPixels);
ObjectAnimator rotation = ObjectAnimator.ofFloat(btnSet, "rotation", 0, 360);
ObjectAnimator alpha = ObjectAnimator.ofFloat(btnSet, "alpha", 1, 0, 1);
AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.playTogether(translationX,rotation,alpha);
// animatorSet.playSequentially();
animatorSet.play(rotation).with(alpha).before(translationX);
animatorSet.setDuration(5000);
animatorSet.setInterpolator(new LinearInterpolator());
animatorSet.start();
}
复制代码
解释:
3.5 xml中编写动画
在/res/animator/目录下新建xml文件:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially" >
<objectAnimator android:duration="2000" android:propertyName="translationX" android:valueFrom="-200" android:valueTo="0" android:valueType="floatType" >
</objectAnimator>
<set android:ordering="together" >
<objectAnimator android:duration="3000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" android:valueType="floatType" >
</objectAnimator>
<set android:ordering="sequentially" >
<objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" >
</objectAnimator>
<objectAnimator android:duration="1500" android:propertyName="alpha" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" >
</objectAnimator>
</set>
</set>
</set>
<!-- 将一个视图先从屏幕外移动进屏幕,而后开始旋转360度,旋转的同时进行淡入淡出操做-->
复制代码
xml中使用的比较少,这里也不详细写。能够参考下面郭霖文章写的。
4.总结
5. 完整demo地址
6. 参考文章
7. 历史文章目录