Android动画总结——View动画、属性动画、帧动画
2018-03-06 15:58
483 查看
在App中合理地使用动画能够获得友好愉悦的用户体验,Android中的动画有View动画、属性动画、帧动画、布局动画、转场动画等,在5.x以后有又新增了矢量动画,这些动画在平常开发中使用较为普遍,所以有必要做一次完整的总结。
View动画使用非常简单,不仅可以通过XML文件来定义动画,同样可以通过Java代码来实现动画过程。
1.Xml文件定义View动画通过xml来定义View动画涉及到一些公有的属性(在AndroidStudio上不能提示):
利用xml文件定义View动画需要在工程的res目录下创建anim文件夹,所有的xml定义的View动画都要放在anim目录下。
渐变
"50"位置点
"50%"位置点
"50%p"位置点
通过定义xml动画资源文件,在Activity中调用:
渐变:
View动画效果
View动画可以设置一个动画执行的监听器:
属性动画的作用效果就是:在一个指定的时间段内将对象的一个属性的属性值动态地变化到另一个属性值。
1.ObjectAnimator
ObjectAnimator实现属性动画
在动画更新的过程中,通过不断去调用对象属性的
属性动画也同样可以通过xml文件来定义,同样在工程的res目录下创建animator文件夹,xml文件定义的
属性动画也同样可以组合使用,通过
通过
AnimatorSet构建属性动画集
通过xml文件定义属性动画集:
xml定义属性动画集
同样,属性动画也可以添加动画执行监听器:
2.ValueAnimator
下面是用
ValueAnimator自定义控件效果图3.TypeEvaluator
泛型
所以我们要用属性动画来执行复杂对象的动画过程,就需要自定义
先来定义一个对象
自定义TypeEvaluator效果图
需要注意的是,系统调用获取控件setter、getter方法是通过反射获取的,属性的名称必须和getter、setter方法名称后面的字符串一致,比如上面的getter、setter方法分别为
帧动画效果图
源码:https://github.com/xiaoyanger0825/AnimationSummary
一、View动画
View动画定义了渐变Alpha、旋转Rotate、缩放Scale、平移Translate四种基本动画,并且通过这四种基本动画的组合使用,可以实现多种交互效果。View动画使用非常简单,不仅可以通过XML文件来定义动画,同样可以通过Java代码来实现动画过程。
1.Xml文件定义View动画通过xml来定义View动画涉及到一些公有的属性(在AndroidStudio上不能提示):
android:duration 动画持续时间 android:fillAfter 为true动画结束时,View将保持动画结束时的状态 android:fillBefore 为true动画结束时,View将还原到开始开始时的状态 android:repeatCount 动画重复执行的次数 android:repeatMode 动画重复模式 ,重复播放时restart重头开始,reverse重复播放时倒叙回放,该属性需要和android:repeatCount一起使用 android:interpolator 插值器,相当于变速器,改变动画的不同阶段的执行速度这些属性是从Animation中继承下来的,在
alpha、
rotate、
scale、
translate标签中都可以直接使用。
利用xml文件定义View动画需要在工程的res目录下创建anim文件夹,所有的xml定义的View动画都要放在anim目录下。
渐变
view_anim_alpha.xml:
<?xml version="1.0" encoding="utf-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromAlpha="1.0" android:toAlpha="0"> </alpha>旋转
view_anim_rotate.xml:
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fillAfter="true" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360"> </rotate>缩放
view_anim_scale.xml:
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="0.5" android:toYScale="0.5"> </scale>平移
view_anim_translate.xml:
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100%" android:toYDelta="100%"> </translate>
rotate、
scale动画的
android:pivotX和
android:pivotY属性、
translate动画的
android:toXDelta和
android:toYDelta属性的取值都可以是都可以数值、百分数、百分数
p,比如:
50、
50%、
50%p,他们取值的代表的意义各不相同:
50表示以View左上角为原点沿坐标轴正方向(
x轴向右,
y轴向下)偏移
50px的位置;
50%表示以View左上角为原点沿坐标轴正方向(
x轴向右,
y轴向下)偏移View宽度或高度的50%处的位置;
50%p表示以View左上角为原点沿坐标轴正方向(
x轴向右,
y轴向下)偏移父控件宽度或高度的50%处的位置(
p表示相对于
ParentView的位置)。
"50"位置点
"50%"位置点
"50%p"位置点
通过定义xml动画资源文件,在Activity中调用:
public void clickToAlpha(View view) { Animation alphaAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_alpha); mTargetView.startAnimation(alphaAnim); } public void clickToRotate(View view) { Animation rotateAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_rotate); mTargetView.startAnimation(rotateAnim); } public void clickToScale(View view) { Animation scaleAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_scale); mTargetView.startAnimation(scaleAnim); } public void clickToTranslate(View view) { Animation translateAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_translate); mTargetView.startAnimation(translateAnim); } public void clickToSet(View view) { Animation setAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_anim_set); mTargetView.startAnimation(setAnim); }2.Java代码实现View动画在平常的业务逻辑中也可以直接用Java代码来实现Veiw动画,Android系统给我们提供了
AlphaAnimation、
RotateAnimation、
ScaleAnimation、
TranslateAnimation四个动画类分别来实现View的渐变、旋转、缩放、平移动画。
渐变:
public void clickToAlpha(View view) { AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); alphaAnimation.setDuration(2000); mTargetView.startAnimation(alphaAnimation); }旋转:
public void clickToRotate(View view) { RotateAnimation rotateAnimation = new RotateAnimation( 0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(2000); mTargetView.startAnimation(rotateAnimation); }缩放:
public void clickToScale(View view) { ScaleAnimation scaleAnimation = new ScaleAnimation( 1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(2000); mTargetView.startAnimation(scaleAnimation); }平移:
public void clickToTranslate(View view) { TranslateAnimation translateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1); translateAnimation.setDuration(2000); mTargetView.startAnimation(translateAnimation); }组合:
public void clickToSet(View view) { AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); alphaAnimation.setDuration(2000); RotateAnimation rotateAnimation = new RotateAnimation( 0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(2000); ScaleAnimation scaleAnimation = new ScaleAnimation( 1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(2000); TranslateAnimation translateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1); translateAnimation.setDuration(2000); AnimationSet animationSet = new AnimationSet(true); animationSet.addAnimation(alphaAnimation); animationSet.addAnimation(rotateAnimation); animationSet.addAnimation(scaleAnimation); animationSet.addAnimation(translateAnimation); mTargetView.startAnimation(animationSet); }
View动画效果
View动画可以设置一个动画执行的监听器:
animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // 动画开始 } @Override public void onAnimationEnd(Animation animation) { // 动画结束 } @Override public void onAnimationRepeat(Animation animation) { //动画重复 } });通过设置监听器可以在动画执行的开始、结束、重复时做一些其他的业务逻辑。
二、属性动画
所谓属性动画,就是改变对象Object的属性来实现动画过程。属性动画是对View的动画的扩展,通过它可以实现更多漂亮的动画效果。同时属性动画的作用对象不仅仅是View,任何对象都可以。
属性动画的作用效果就是:在一个指定的时间段内将对象的一个属性的属性值动态地变化到另一个属性值。
1.ObjectAnimator
ObjectAnimator是最常用的属性动画执行类。
private void startJavaPropertyAnimator() { ObjectAnimator .ofFloat(mImageView, "rotationY", 0f, 360f) .setDuration(2000) .start(); }上面的代码就是通过
ObjectAnimator在2000ms内将
mImageView的
rotationY属性的属性值从
0f变化的
360f。
ObjectAnimator实现属性动画
ObjectAnimtor可以用
ofInt、
ofFloat、
ofObject等静态方法,传入动画作用的
目标Object、属性字段、属性开始值、属性中间值、属性结束值等参数来构造动画对象。
在动画更新的过程中,通过不断去调用对象属性的
setter方法改变属性值,不断重绘实现动画过程。如果没有给定动画开始属性值,那么系统会通过反射去获取
Object对象的初始值作为动画的开始值。
属性动画也同样可以通过xml文件来定义,同样在工程的res目录下创建animator文件夹,xml文件定义的
objectAnimator动画要放在该文件夹下。
property_animator.xml:
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:propertyName="rotationY" android:valueFrom="0" android:valueTo="360" android:valueType="floatType"> </objectAnimator>Java代码调用:
private void startXmlPropertyAnimator() { Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.property_animator); animator.setTarget(mImageView); animator.start(); }最终效果如上图。
属性动画也同样可以组合使用,通过
AnimatorSet类和xml文件的
set标签都可以同时改变对象的多个属性,实现更加丰富的动画效果。
通过
AnimatorSet创建动画集:
private void startJavaPropertyAnimatorSet() { Animator scaleXAnimator = ObjectAnimator.ofFloat(mImageView, "scaleX", 1, 0.5f); scaleXAnimator.setDuration(2000); Animator scaleYAnimator = ObjectAnimator.ofFloat(mImageView, "scaleY", 1, 0.5f); scaleYAnimator.setDuration(2000); Animator rotationXAnimator = ObjectAnimator.ofFloat(mImageView, "rotationX", 0, 360); rotationXAnimator.setDuration(2000); Animator rotationYAnimator = ObjectAnimator.ofFloat(mImageView, "rotationY", 0, 360); rotationYAnimator.setDuration(2000); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(scaleXAnimator) .with(scaleYAnimator) .before(rotationXAnimator) .after(rotationYAnimator); animatorSet.start(); }
AnimatorSet通过
before、
with、
after三个方法可以组合多个属性动画,
with表示与给定动画同时执行,
before在给定动画执行之前执行,
after表示在给定动画执行之后执行。
AnimatorSet构建属性动画集
通过xml文件定义属性动画集:
property_animator_set.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:duration="2000" android:propertyName="scaleX" android:valueFrom="1" android:valueTo="0.5" android:valueType="floatType"/> <objectAnimator android:duration="2000" android:propertyName="scaleY" android:valueFrom="1" android:valueTo="0.5" android:valueType="floatType"/> <objectAnimator android:duration="2000" android:propertyName="alpha" android:valueFrom="1" android:valueTo="0.5" android:valueType="floatType"/> </set>在Java代码中调用属性动画集:
private void startxmlPropertyAnimatorSet() { Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.property_animator_set); animator.setTarget(mImageView); animator.start(); }
xml定义属性动画集
同样,属性动画也可以添加动画执行监听器:
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) { // 动画重复 } });在监听到属性动画开始、结束、取消、重复时可以去做一些其他的逻辑业务。
2.ValueAnimator
ValueAnimator是
ObjectAnimator的父类,它继承自
Animator。
ValueAnimaotor同样提供了
ofInt、
ofFloat、
ofObject等静态方法,传入的参数是动画过程的开始值、中间值、结束值来构造动画对象。可以将
ValueAnimator看着一个值变化器,即在给定的时间内将一个目标值从给定的开始值变化到给定的结束值。在使用
ValueAnimator时通常需要添加一个动画更新的监听器,在监听器中能够获取到执行过程中的每一个动画值。
private void startValueAnimator() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(300); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 动画更新过程中的动画值,可以根据动画值的变化来关联对象的属性,实现属性动画 float value = (float) animation.getAnimatedValue(); Log.d("ValueAnimator", "动画值:" + value); } }); }在300ms内将数值0变化到1的动画值的变化log:
02-25 23:16:57.586 D/ValueAnimator: 动画值:0.0 02-25 23:16:57.596 D/ValueAnimator: 动画值:0.007902175 02-25 23:16:57.616 D/ValueAnimator: 动画值:0.029559612 02-25 23:16:57.636 D/ValueAnimator: 动画值:0.066987276 02-25 23:16:57.646 D/ValueAnimator: 动画值:0.118102014 02-25 23:16:57.666 D/ValueAnimator: 动画值:0.18128797 02-25 23:16:57.686 D/ValueAnimator: 动画值:0.2545482 02-25 23:16:57.706 D/ValueAnimator: 动画值:0.33063102 02-25 23:16:57.716 D/ValueAnimator: 动画值:0.4166157 02-25 23:16:57.736 D/ValueAnimator: 动画值:0.5052359 02-25 23:16:57.746 D/ValueAnimator: 动画值:0.5936906 02-25 23:16:57.766 D/ValueAnimator: 动画值:0.67918396 02-25 23:16:57.786 D/ValueAnimator: 动画值:0.7545208 02-25 23:16:57.796 D/ValueAnimator: 动画值:0.82671034 02-25 23:16:57.826 D/ValueAnimator: 动画值:0.88857293 02-25 23:16:57.836 D/ValueAnimator: 动画值:0.93815327 02-25 23:16:57.856 D/ValueAnimator: 动画值:0.9721882 02-25 23:16:57.876 D/ValueAnimator: 动画值:0.99384415 02-25 23:16:57.886 D/ValueAnimator: 动画值:1.0
ValueAnimator的使用一般会结合更新监听器
AnimatorUpdateListener,大多数时候是在自定义控件时使用。
下面是用
ValueAnimator自定义控件实现动画打开关闭效果。
expanded_veiw.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:divider="@drawable/divider" android:orientation="vertical" android:showDividers="middle"> <LinearLayout android:id="@+id/ll_expanded_question" android:layout_width="match_parent" android:layout_height="48dp" android:gravity="center_vertical"> <TextView android:id="@+id/tv_expanded_question" android:layout_width="0dp" android:layout_height="48dp" android:layout_weight="1" android:gravity="center_vertical" android:padding="8dp" android:text="如何把一本很难的书看懂?" android:textColor="#999999" android:textSize="16sp"/> <ImageView android:id="@+id/iv_expanded_indicator" android:layout_width="16dp" android:layout_height="16dp" android:layout_marginRight="16dp" android:src="@drawable/img_up"/> </LinearLayout> <TextView android:id="@+id/tv_expanded_answer" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" android:text="多读几遍。真的特别有用。至少看三遍。从开头看,看到中间,重头再来,再看得多一点,在从新开始,建议看到快结束时再从新开始。" android:textColor="#999999" android:textSize="16sp"/> </LinearLayout>
public class ExpandedView extends FrameLayout { private TextView mTvAnswer; private boolean isClosed; private ImageView mIvIndicator; public ExpandedView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { View view = LayoutInflater.from(context).inflate(R.layout.expanded_view, this, true); LinearLayout llQuestion = (LinearLayout) view.findViewById(R.id.ll_expanded_question); llQuestion.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { anim(); } }); mTvAnswer = (TextView) view.findViewById(R.id.tv_expanded_answer); mIvIndicator = (ImageView) view.findViewById(R.id.iv_expanded_indicator); } private void anim() { // 指示器旋转 ValueAnimator valueAnimator1 = isClosed ? ValueAnimator.ofFloat(180, 0) : ValueAnimator.ofFloat(0, 180); valueAnimator1.setDuration(500); valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); mIvIndicator.setRotation(value); } }); valueAnimator1.start(); // 打开开关闭操作 final int answerHeight = mTvAnswer.getMeasuredHeight(); ValueAnimator valueAnimator2 = isClosed ? ValueAnimator.ofInt(-answerHeight, 0) : ValueAnimator.ofInt(0, -answerHeight); valueAnimator2.setDuration(500); final MarginLayoutParams params = (MarginLayoutParams) mTvAnswer.getLayoutParams(); valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int) animation.getAnimatedValue(); params.bottomMargin = value; mTvAnswer.setLayoutParams(params); } }); valueAnimator2.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { isClosed = !isClosed; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); valueAnimator2.start(); } }
ValueAnimator自定义控件效果图3.TypeEvaluator
ObjectAnimator和
ValueAnimator都有
ofObject方法,传入的都有一个
TypeEvaluator类型的参数。
TypeEvaluator是一个接口,里面也只有一个抽象方法:
public T evaluate(float fraction, T startValue, T endValue);再看
ofInt方法中没有传入该参数,但实际上调用
ofInt方法时,系统已经有实现了
TypeEvaluator接口的
IntEvaluator,它的源码也非常简单:
public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); }
fraction范围为0到1,表示动画执行过程中已完成程度。
泛型
T即为动画执行的属性类型。
所以我们要用属性动画来执行复杂对象的动画过程,就需要自定义
TypeEvaluator,实现动画逻辑。
先来定义一个对象
public class Circle { private int raduis; // 半径 private int color; // 颜色 private int elevation; // 高度 public Circle(int raduis, int color, int elevation) { this.raduis = raduis; this.color = color; this.elevation = elevation; } public int getRaduis() { return raduis; } public void setRaduis(int raduis) { this.raduis = raduis; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } public int getElevation() { return elevation; } public void setElevation(int elevation) { this.elevation = elevation; } }
CircleEvaluator,实现
TypeEvaluator接口:
public class CircleEvaluator implements TypeEvaluator<Circle> { @Override public Circle evaluate(float fraction, Circle startValue, Circle endValue) { int startRaduis = startValue.getRaduis(); int endRaduis = endValue.getRaduis(); int raduis = (int) (startRaduis + fraction * (endRaduis - startRaduis)); int startColor = startValue.getColor(); int endColor = endValue.getColor(); int startColorRed = Color.red(startColor); int startColorGreen = Color.green(startColor); int startColorBlue = Color.blue(startColor); int endColorRed = Color.red(endColor); int endColorGreen = Color.green(endColor); int endColorBlue = Color.blue(endColor); int colorRed = (int) (startColorRed + fraction * (endColorRed - startColorRed)); int colorGreen = (int) (startColorGreen + fraction * (endColorGreen - startColorGreen)); int colorBlue = (int) (startColorBlue + fraction * (endColorBlue - startColorBlue)); int color = Color.rgb(colorRed, colorGreen, colorBlue); int startElevation = startValue.getElevation(); int endElevation = endValue.getElevation(); int elevation = (int) (startElevation + fraction * (endElevation - startElevation)); return new Circle(raduis, color, elevation); } }自定义控件CircleView,将Circle作为它的一个属性:
public class CircleView extends View { private Circle circle; private Paint mPaint; public CircleView(Context context, AttributeSet attrs) { super(context, attrs); circle = new Circle(168, Color.RED, 0); mPaint = new Paint(); mPaint.setAntiAlias(true); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); setElevation(circle.getElevation()); mPaint.setColor(circle.getColor()); canvas.drawCircle(getMeasuredHeight() / 2, getMeasuredHeight() / 2, circle.getRaduis(), mPaint); } public void setCircle(Circle circle) { this.circle = circle; postInvalidate(); } public Circle getCircle() { return circle; } }
ObjectAnimator使用:
private void start1() { Circle startCircle = new Circle(168, Color.RED, 0); Circle middleCircle = new Circle(300, Color.GREEN, 15); Circle endCircle = new Circle(450, Color.BLUE, 30); ObjectAnimator.ofObject(mCircleView, "circle", new CircleEvaluator(), startCircle, middleCircle, endCircle) .setDuration(5000) .start(); }
ValueAnimator使用:
private void start2() { Circle startCircle = new Circle(168, Color.RED, 0); Circle middleCircle = new Circle(300, Color.GREEN, 15); Circle endCircle = new Circle(450, Color.BLUE, 30); ValueAnimator valueAnimator = ValueAnimator.ofObject(new CircleEvaluator(), startCircle, middleCircle, endCircle); valueAnimator.setDuration(5000); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Circle circle = (Circle) animation.getAnimatedValue(); mCircleView.setCircle(circle); } }); valueAnimator.start(); }
自定义TypeEvaluator效果图
需要注意的是,系统调用获取控件setter、getter方法是通过反射获取的,属性的名称必须和getter、setter方法名称后面的字符串一致,比如上面的getter、setter方法分别为
getCircle、
setCircle,那么属性名字就必须为
circle。
三、帧动画
帧动画需要开发者制定好动画每一帧,系统一帧一帧的播放图片。private void start1() { AnimationDrawable ad = new AnimationDrawable(); for (int i = 0; i < 7; i++) { Drawable drawable = getResources().getDrawable(getResources().getIdentifier("ic_fingerprint_" + i, "drawable", getPackageName())); ad.addFrame(drawable, 100); } ad.setOneShot(false); mImageView.setImageDrawable(ad); ad.start(); }帧动画同样也可以在xml文件中配置,直接在工程
drawable目录新建
animation-list标签:
<?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/ic_fingerprint_0" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_1" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_2" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_3" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_4" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_5" android:duration="100"/> <item android:drawable="@drawable/ic_fingerprint_6" android:duration="100"/> </animation-list>
private void start2() { mImageView.setImageResource(R.drawable.frame_anim); AnimationDrawable animationDrawable = (AnimationDrawable) mImageView.getDrawable(); animationDrawable.start(); }其中
android:onshot属性和
setOneShot方法表示是否只执行一次。
AnimationDrawable实际是上是一个
Drawable动画,动画执行的过程总会给你不断重绘
Drawable的每一帧图像,实现动态播放效果。
帧动画效果图
源码:https://github.com/xiaoyanger0825/AnimationSummary
相关文章推荐
- Android动画总结——View动画、属性动画、帧动画
- Android动画总结——View动画、属性动画、帧动画
- Android动画总结——View动画、属性动画、帧动画
- Android动画总结——View动画、属性动画、帧动画
- Android动画总结——View动画、属性动画、帧动画
- Android动画总结——View动画、属性动画、帧动画
- android中属性动画的bug,以及ViewCompat
- Android 属性动画 实现view翻转 旋转 平移 拉伸 透明度 背景颜色变换
- android 自定义view+属性动画实现充电进度条
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法
- Android开发-RecyclerView-AndroidStudio(五)属性动画(2)MoveDuration
- Android开发总结笔记 属性动画(中) 4-2
- Android中Imageview的Scale Type属性总结
- Android为ViewPager增加切换动画——使用属性动画.
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法
- android动画基础(一) View动画和属性动画
- android 帧动画,补间动画,属性动画的简单总结
- Android游戏开发---View线程绘动画与显示总结
- android:ViewPager动画总结
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法