持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
前面讲完了视图动画篇 Android自定义view基础之Animation(动画)-视图动画篇 - 掘金 (juejin.cn)
帧动画
对一系列的图片进行逐个反映,从而形成动画效果
逐帧动画是用Drawable的一个子类AnimationDrawable类来实现的
使用
-
第一步
在Drawable目录下新建Drawable Resource file,类型选择为animation-list
-
第二步
准备图片,网上搜逐帧动画就会有很多资源
-
第三步
编写代码xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/img_one" android:duration="200"/>
<item android:drawable="@drawable/img_tow" android:duration="200"/>
<item android:drawable="@drawable/img_three" android:duration="200"/>
</animation-list>
属性 oneshot代表是否只只播放一次,否则循环播放
- 第四步
在activity中编写代码
ImageView imageView= findViewById(R.id.imageView);
imageView.setBackgroundResource(R.drawable.myframeanimation);//设置背景为帧动画
AnimationDrawable background = (AnimationDrawable)imageView.getBackground();//拿到设置的背景
background.start();//开始动画
之后重新运行你的程序就可以看到效果了
属性动画
属性动画与前面两种动画的区别是其
属性值会真正发生改变
属性动画分三类
- ViewPropertyAnimator
- ObjectAnimatior
- ValueAnimator
ViewPropertyAnimator
这个动画与其他两个动画不同的是它不能自定义属性,只能使用系统自带的属性(平移,放缩,透明度,旋转),相对来说它更像视图动画,只不过它的属性值是真正改变的。
使用
view.animate();方法就可以返回一个ViewProperty对象
如上图这是基本属性,同样Scale rotate 也有
by表示在原来的基础上变化多少
其余的表示移动到一个什么样的位置
- 可以组合来使用一系列的动画
imageView.animate().alpha(1).scaleY(1).scaleX(1);
- 配置方法
ObjectAnimation
- 基本使用
ObjectAnimator animator = ObjectAnimator.ofFloat(
imageView, "translationX", 0,600,500,600);
animator.setDuration(2000);
animator.start();
objectAnimator提供了一系列的of方法
第一个参数为你要操作的view,如上述代码为imagineView
第二个参数为要操作的属性,系统有内置的一些基础操作,当然我们也可以自定义属性
第三个参数为可变参数,也就是一个数组,你选用什么类型的函数就填什么类型的数据类型,比如 ofFloat 就填浮点型,ofObject 就填某一个类的对象
在填入的数组中第一号元素为
初始态,最后一位元素为最终态,中间元素为中间过渡态eg在上述代码中imageview会沿着x方向0 ->600->500->600
自定义属性
在上述我们所填入的translateX,其实,这个方法会在View内部拼接为该类属性的setter方法,并触发重绘
有没有什么启发呢?
我们在自定义view的时候是不是可以用到,例如下面代码,来制作一个圆形进度条
public class PathView extends View {
public PathView(Context context) {
super(context);
}
public PathView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public PathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public PathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
Paint paint=new Paint();
public float getProgress() {
return progress;
}
public void setProgress(float progress) {
this.progress = progress;
invalidate();//每次数值改变触发重绘
}
private float progress;
@Override
protected void onDraw(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAntiAlias(true);
canvas.drawArc(rectF,135,progress*2.7f,false,paint);//绘制进度条
//一个百分比代表 3.6度
paint.setStrokeWidth(3);
paint.setTextSize(50);
int a=(int) progress;
canvas.drawText((a)+"%",210,250,paint);//绘制百分比
}
}
让后在activity中
ObjectAnimator animator=ObjectAnimator.ofFloat(pathView,"progress",0,100,60);
animator.setDuration(3000);
animator.start();
如上代码所示 定义一个progress 变量,改写其set方法,其实就是加入invalidate触发onDraw 方法来重绘,不断重绘就会触发动画
设置多个动画播放顺序
AnimatorSet
AnimatorSet animatorSet = new AnimatorSet();
// 两个动画依次执行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
// 两个动画同时执行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式来精确配置各个 Animator 之间的关系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
-
after(Animator anim):将现有动画插入到传入的动画之后执行after(long delay):将现有动画延迟指定毫秒后执行before(Animator anim): 将现有动画插入到传入的动画之前执行with(Animator anim):将现有动画和传入的动画同时执行
ValueAnimator
valueAnimator:这个动画是针对属性的值进行动画的 ,不会对UI造成改变,不能直接实现动画效果。需要通过对动画的监听去做一些操作,在监听中将这个值设置给对应的属性,对应的属性才会改变。
ValueAnimator sunAnimator = ValueAnimator.ofFloat(startAngle, currentAngle);
sunAnimator.setDuration(duration);
sunAnimator.addUpdateListener(animation -> {
mCurrentAngle = (float) animation.getAnimatedValue();//修改属性值
invalidate();//触发onDRaw 方法来重绘
});
sunAnimator.start();//开始动画
相对来说
ValueAnimator更像是一个数值改变器,我们获取实时的数值对我们的属性赋值来生成动画