文章首发于个人博客
任何形式的转载都请联系作者获得授权并注明出处。
一、基本概念
属性动画就是在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。
二、动画
1、View中的方法
我们可以对View调用以下属性实现动画
View中的方法 | 功能 |
---|---|
setTranslationX() 、setTranslationY() 、setTranslationZ()
|
设置X、Y、Z轴平移 |
setX() 、setX() 、setX()
|
设置X、Y、Z轴绝对位置 |
setRotation() 、setRotationX() 、setRotationY()
|
设置平面、X、Y轴旋转 |
setScaleX() 、setScaleY()
|
设置X、Y方向缩放 |
setAlpha() |
设置透明度 |
2、ValueAnimator
属性动画机制中最核心的一个类,ObjectAnimator和ViewPropertyAnimator都是通过这个这个实现的。ValueAnimator是通过不断控制值的变化,再不断添加属性,从而实现动画效果
使用方法
- 初始化ValueAnimator,设置各种属性
- 给ValueAnimator设置监听器,通过getAnimatedValue()拿到变化值后更新控件。
常用方法 | 功能 |
---|---|
ofInt() |
返回一个int型变化的ValueAnimator |
ofFloat() |
返回一个float型变化的ValueAnimator |
ofObject |
返回一个object型变化的ValueAnimator。 |
1.1、设置颜色变化
我们这里并没有使用ofArgb
这个属性,因为这个方法是在API21以上使用的,在低版本上不兼容。
final View view = findViewById(R.id.view);
//以整型数值的形式,过渡到结束值
ValueAnimator animator = ValueAnimator.ofInt(0xffff00ff, 0xffffff00, 0xffff00ff);
//设置求值器
animator.setEvaluator(new ArgbEvaluator());
//设置动画的播放时长
animator.setDuration(1000);
//设置动画重复播放次数,ValueAnimator.INFINITE为无限重复
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
Log.i(TAG, "onAnimationUpdate: "+currentValue);
view.setBackgroundColor(currentValue);
view.requestLayout();
}
});
animator.start();
1.2、ofObject()
的使用
ofInt和ofFloat是针对Int值和Float值的变化,但是,我们只能控制一个值的变化,但是当我们需要实现多值变化时,它们就不再满足我们的需求。
//设置变化的值
ValueObject startObjectVal = new ValueObject(1f, 0);
ValueObject endObjectVal = new ValueObject(0f, 360);
ValueAnimator animator = ValueAnimator.ofObject(new Evaluator(), startObjectVal, endObjectVal);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setAlpha(((ValueObject) animation.getAnimatedValue()).alphaValue);
//可以设置各种动画
view.setRotation(((ValueObject) animation.getAnimatedValue()).rotateValue);
view.requestLayout();
}
});
animator.start();
》》设置估值器,估值器的作用觉得值得变化顺序《《
//下面具体讲解
class Evaluator implements TypeEvaluator<ValueObject> {
@Override
public ValueObject evaluate(float fraction, ValueObject startValue, ValueObject endValue) {
float alphaValue = startValue.alphaValue + (endValue.alphaValue - startValue.alphaValue) * fraction;
float rotateValue = startValue.rotateValue + (endValue.rotateValue - startValue.rotateValue) * fraction;
return new ValueObject(alphaValue, rotateValue);
}
}
//创建对象,保存透明度和旋转的值得变化
class ValueObject {
float alphaValue;//透明度
float rotateValue;//旋转
ValueObject(float alphaValue, float rotateValue) {
this.alphaValue = alphaValue;
this.rotateValue = rotateValue;
}
}
1.3、属性和方法整理
常用的属性
方法 | 解释 | 方法 | 解释 |
---|---|---|---|
setDuration |
设置动画总时长,单位毫秒。 | getDuration |
获取动画总时长 |
setFrameDelay |
设置每一帧之间间隔多少毫秒 | getFrameDelay |
获取每一帧之间间隔多少毫秒 |
setInterpolator |
设置动画的插值器 | getInterpolator |
获取当前使用的插值器 |
setRepeatCount |
设置重复次数 | getRepeatCount |
获取重复次数 |
setRepeatMode |
设置重复模式。有RESTART(正序)和REVERSE(倒序) | getRepeatMode |
获取重复模式 |
setStartDelay |
设置开始前延迟毫秒数 | getStartDelay |
获取开始前延迟毫秒数 |
getAnimatedValue |
获取计算出来的当前属性值 | getAnimatedValue |
获取计算出来的当前某个属性的值 |
setEvaluator |
设置求值器 | setFloatValues |
设置Float型变化值,设置初始值、中间值、结束值 |
setIntValues |
设置Int型变化值,设置初始值、中间值、结束值 | setObjectValues |
设置Object型变化值,设置初始值、中间值、结束值 |
常用的方法
方法 | 解释 | 方法 | 解释 |
---|---|---|---|
addUpdateListener |
添加值变化监听器 | addUpdateListener |
添加动画状态监听器 |
start |
开始动画 | pause |
暂停动画 |
resume |
继续动画 | cancel |
取消动画 |
end |
动画结束 | reverse |
倒序播放动画 |
isRunning |
判断是否在正在运行 | isStarted |
判断是的开始播放 |
1.4、估值器和插值器(重点)
估值器--TypeEvaluator:决定值的具体变化顺序
估值器的使用我们上面已经学习过了,在这里对估值器的具体使用简单的解释。
//实现了TypeEvaluator接口
public class FloatEvaluator implements TypeEvaluator {
/**
* fraction:表示动画完成度
* startValue:动画的初始值
* endValue:动画的结束值
* /
public Object evaluate(float fraction, Object startValue, Object endValue) {
//用初始值加上动画完成度乘以结束值和初始值之间的差值
}
}
插值器--Interpolator:决定值的速度变化顺序
使用方法:
setInterpolator(Interpolator interpolator)//设置速度插值器
常用的插值器:
- LinearInterpolator:线性匀速变化
- AccelerateDecelerateInterpolator:先加速再减速
- AccelerateInterpolator:持续加速
- DecelerateInterpolator:持续减速直到 0
- AnticipateInterpolator:先回拉一下再进行正常动画轨迹
- OvershootInterpolator:动画会超过目标值一些,然后再弹回来
- AnticipateOvershootInterpolator:先回拉一下再进行正常动画轨迹,最后动画会超过目标值一些,然后再弹回来
- BounceInterpolator:在目标值来回跳动
3、ObjectAnimator
直接对对象的属性值进行改变操作,从而实现动画效果,内部是有ValueAnimator实现,因此其也有ofXXX()方法,这里接受的参数不一样了,具体的就不整理了,常用属性和常用方法和ValueAnimator一致
使用方法:
- 对于自定义控件,使用
setter
/getter
方法; - 调用
ObjectAnimator.ofXXX()
创建ObjectAnimator
对象,设置常用属性。 - 调用
start()
方法执行动画
方法:ofFloat(Object target, String propertyName, float... values)
参数:
target:我们需要控制动画的对象
-
propertyName:设置动画效果(传入任意属性值)
这里传入的参数,其实是调用了
ValueAnimator
的setXXX()
方法和getXXX()
方法,具体的代码就不贴了。-
alpha
:透明度 -
rotation
,RotationX
,RotationY
:旋转 -
translationX
,translationY
:平移 -
ScaleX
,scaleY
:缩放 - values:自定义属性
-
values
:值
》》自定义圆形进度条《《
完整代码在线地址:Github在线地址
ProPress.java
我们在Activity中,给动画设置了一个属性
progress
,我们在ProPress.java
中,用getProgress()
和setProgress
方法,这样系统会自动调用该对象属性的set() & get()方法进行赋值。
/**
* Created by Active_Loser on 2018/10/22.
* Content: 自定义圆形进度条
*/
public class ProPress extends View {
//.....
private int progress = 0;
public float getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
invalidate();
}
//.....
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
//绘制圆弧
RectF arcRectF = new RectF(20, 20, width-20, height-20);
//progress设置值为0-100,因此需要乘3.6
canvas.drawArc(arcRectF, 135, progress * 3.6f, false, mArcPaint);
canvas.drawText(progress + "%", width/2, height/2-(mArcPaint.ascent() + mArcPaint.descent()) / 2, mTextPaint);
}
}
XML:
<com.example.active.loser.views.level3.ProPress
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:id="@+id/view"/>
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ProPress view = findViewById(R.id.view);
// 创建 ObjectAnimator 对象
ObjectAnimator animator = ObjectAnimator.ofInt(view, "progress", 0, 100);
//持续时长4秒
animator.setDuration(4000);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.start();
}
4、ViewPropertyAnimator
ValueAnimator、ObjectAnimator、ViewPropertyAnimator三者使用难度和灵活性逐渐递减,因此我们尽量选择简单的使用
使用方法
view.animate().动画();
常用的动画如下表所示:
View中的方法 | 对于中的方法ViewPropertyAnimator | 功能 |
---|---|---|
setTranslationX() |
translationX() 、translationXBy() 、 |
设置X轴平移 |
setTranslationY() |
translationY() 、translationYBy()
|
设置Y轴平移 |
setTranslationZ() |
translationZ() 、translationZBy()
|
设置Z轴平移 |
setX() 、setX() 、setX()
|
x() 、xBy() 、y() 、yBy() 、z() 、zBy()
|
设置X、Y、Z轴绝对位置 |
setRotation() |
rotation() 、rotationBY()
|
设置平面轴旋转 |
setRotationX() |
rotationX() 、rotationXBy()
|
设置X轴旋转 |
setRotationY() |
rotationY() 、rotationYBy()
|
设置Y轴旋转 |
setScaleX() |
scaleX() 、scaleX()By
|
设置X方向缩放 |
setScaleY() |
scaleY() 、scaleYBy()
|
设置Y方向缩放 |
setAlpha() |
alpha() 、alphaBy()
|
设置透明度 |
特点:
-
有
by
:变化偏移、无by
:变化到即:加上By的意思是,继续动画这么多数值,不加By的意思是动画到这个数值。
简单的使用:
view.animate()
.setDuration(5000)
.zBy(10)
.setInterpolator(new BounceInterpolator())
.setStartDelay(1000)
.withLayer()//是否开启硬件加速
//监听
.setListener(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) {
}
})
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
}
})
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.start();