100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 深入理解Android之动画

深入理解Android之动画

时间:2019-04-19 16:06:06

相关推荐

深入理解Android之动画

Android 里动画从用途上讲,可以分为三类View Animation(View动画)又称 Tween Animation(补间动画)、DrawableAnimation(帧动画)和 Property Animation(属性动画)。 这篇文章,我就介绍一下这三种类型的动画。

目录:

(一)View动画

(二)帧动画

(三)属性动画

(一)View动画

View动画是基于View的渐变动画,只改变了View的绘制效果,View的实际属性值并未改变。

View动画的对象是View,它支持4种动画效果:

TranslateAnimation(平移动画)

ScaleAnimation(缩放动画)

RotateAnimation(旋转动画)

AlphaAnimation(透明度动画)

并提供了AnimationSet动画集合。实现原理是每次绘图时View所在的ViewGroup中的dispathDraw,流程如下图:

除了这四种典型的动画效果外,帧动画本质上也属于View动画。但是帧动画的表现形式和这4种动画不太一样,因此通常单拎出来归为一类。

这四种动画既可以通过XML来定义,也可以通过代码来动态创建。

使用XML之前我们首先需要创建XML文件,路径为:res/anim/filename.xml。

1.透明度动画

代码实现:

AlphaAnimation animation = new AlphaAnimation(0, 1);// 透明度0变化到透明度为1animation.setDuration(1000);// 动画执行时间1stextView.startAnimation(animation);XML实现:

<set xmlns:android="/apk/res/android"> <alpha android:duration="1000" android:fromAlpha="0" android:interpolator="@android:anim/accelerate_interpolator" android:repeatCount="3" android:fillAfter="true" android:repeatMode="restart" android:toAlpha="1" /></set>

2. 旋转动画

代码实现:

RotateAnimation animation = new RotateAnimation(0,360, 100, 100);animation.setDuration(1000);animation.setFillAfter(true); // 设置保持动画最后的状态animation.setInterpolator(new AccelerateInterpolator()); // 设置插入器textView.startAnimation(animation);

还可以通过系统提供参数来控制动画

new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);xml实现:

<rotate xmlns:android="/apk/res/android" android:duration="1000" android:fromDegrees="0.0" android:interpolator="@android:anim/linear_interpolator" android:pivotX="50.0%" android:pivotY="50.0%" android:repeatCount="infinite" android:toDegrees="360.0"></rotate>参数说明

fromDegrees为动画起始时的旋转角度,此角度是当前为0及360,设置其他值则先跳至该角度的位置再由from - to的值: 负则正向转,正则反向转

toDegrees为动画旋转到的角度

pivotXType为动画在X轴相对于物件位置类型

pivotXValue为动画相对于物件的X坐标的开始位置,此值是以本身原始位置为原点,即如设为20%p,则向右移动父控件的20%位移,为负数则向左移

pivotYType为动画在Y轴相对于物件位置类型

pivotYValue为动画相对于物件的Y坐标的开始位置,此值是以本身原始位置为原点,即如设为20%p,则向下移动父控件的20%位移,为负数则向上移

3. 位移动画

代码实现:

TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 200);translateAnimation.setDuration(1000);textView.startAnimation(translateAnimation);xml实现:

<translate android:duration="1000" android:fillAfter="true" android:fromXDelta="0" android:fromYDelta="0" android:repeatCount="3" android:toXDelta="200" android:toYDelta="000"></translate>参数说明

fromXDelta为动画起始时 X坐标上的移动位置

toXDelta为动画结束时 X坐标上的移动位置

fromYDelta为动画起始时Y坐标上的移动位置

toYDelta为动画结束时Y坐标上的移动位置

4. 缩放动画

代码实现:

ScaleAnimation animation = new ScaleAnimation(0,1,0,1);animation.setDuration(1000);textView.startAnimation(animation);

缩放动画也可以设置缩放的中心点

ScaleAnimation animation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);xml实现:

<scale android:duration="1000" android:fillAfter="true" android:fillBefore="true" android:fromXScale="0.0" android:fromYScale="0.0" android:interpolator="@android:anim/linear_interpolator" android:pivotX="50%" android:pivotY="50%" android:repeatCount="-1" android:repeatMode="reverse" android:startOffset="2000" android:toXScale="1.0" android:toYScale="1.0"></scale>参数说明

fromX为动画起始时 X坐标上的伸缩尺寸 0.0表示收缩到没有

toX为动画结束时 X坐标上的伸缩尺寸 1.0表示正常无伸缩

fromY为动画起始时Y坐标上的伸缩尺寸 值小于1.0表示收缩

toY为动画结束时Y坐标上的伸缩尺寸 值大于1.0表示放大

pivotXType为动画在X轴相对于物件位置类型

pivotXValue为动画相对于物件的X坐标的开始位置

pivotXType为动画在Y轴相对于物件位置类型

pivotYValue为动画相对于物件的Y坐标的开始位置

5. anim文件使用

Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);textView.startAnimation(animation);

6. 动画集合

AnimationSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。

AnimationSet animationSet = new AnimationSet(true);animationSet.setDuration(1000);AlphaAnimation alpha=new AlphaAnimation(0,1);alpha.setDuration(1000);animationSet.addAnimation(alpha);TranslateAnimation translate = new TranslateAnimation(100, 200, 0, 200);translate.setDuration(1000);animationSet.addAnimation(translate);textView.startAnimation(animationSet);

7. 动画监听

对于动画事件,Android也提供了开始、结束和重复事件的监听方法。

animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { }});

8. View动画的特殊使用

(1)LayoutAnimation

layoutAnimation作用于viewGroup,为ViewGroup制定一个动画,他的每个子元素都会按照这种动画出场。这种效果常被用在ListView上。使用步骤如下:

1)定义LayoutAnimation

<?xml version="1.0" encoding="utf-8"?><layoutAnimation xmlns:android="/apk/res/android" android:delay="0.5" android:animationOrder="reverse" android:animation="@anim/animation_scale"></layoutAnimation>

android:delay 表示子元素开始动画的时间延迟

android:animationOrder表示子元素动画的顺序,有三个选项:

normal:顺序显示

reverse:表示逆向显示

random:随机播放

android:animation为子元素指定具体的入场动画

2)为子元素制定具体的入场动画

<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="/apk/res/android" android:fromXScale="0.1" android:toXScale="1.5" android:fromYScale="0.1" android:toYScale="1.5" android:duration="2000"></scale>

3)为GroupView指定LayoutAnimation属性

<ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@ id/xlv" android:layoutAnimation="@anim/animation_layout" android:background="#fff4f7f9" android:divider="#ddd" android:dividerHeight="1.0px" android:listSelector="#999"></ListView>

除了在XML文件中进行设置,我们还可以使用代码来完成:

Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);LayoutAnimationController controller = new LayoutAnimationController(animation);controller.setDelay(0.5f);controller.setOrder(LayoutAnimationController.ORDER_NORMAL);listView.setLayoutAnimation(controller);

(2)Transition Animation(过渡动画)

Transition也是基于属性动画的,与属性动画不同的是,它是可以实现布局改变的过渡动画。由于Transition的内容较多,具体请参照Android Transition Framework(过渡动画框架)。

(二)帧动画

帧动画就是加载一系列Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放,就像电影胶片。在代码中定义动画帧,使用AnimationDrawable类;XML文件能更简单的组成动画帧,在res/drawable文件夹,使用<animation-list>采用<item>来定义不同的帧。只能设置的属性是动画间隔时间。

<animation-list xmlns:android="/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/img0" android:duration="100"/> <item android:drawable="@drawable/img1" android:duration="100"/> <item android:drawable="@drawable/img2" android:duration="100"/> <item android:drawable="@drawable/img3" android:duration="100"/> <item android:drawable="@drawable/img4" android:duration="100"/> <item android:drawable="@drawable/img5" android:duration="100"/> ...</animation-list>

然后对组件的属性(如ImageView的android:src/android:background)直接设置即可。

ImageView iv = findViewById(R.id.image_view);//iv.setBackgroundResource(R.drawable.drawable_animation); //获取背景,并将其强转成AnimationDrawable AnimationDrawable animationDrawable = (AnimationDrawable) iv.getBackground(); //判断是否在运行 if(!animationDrawable.isRunning()){ //开启帧动画 animationDrawable.start(); }

注意:帧动画的使用非常简单,但是比较容易引起OOM,所以在使用帧动画时应尽量避免使用过多尺寸较大的图片。

(三)属性动画

属性动画的对象除了传统的View对象,还可以是Object对象,动画之后,属性值被实实在在的改变了。因此,属性动画能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来刷新。

属性动画是在 Android 3.0 开始引入的新的动画形式,不过说它新只是相对的,它已经有好几年的历史了,而且现在的项目中的动画 99% 都是用的它,极少再用到 View Animation 了。属性动画不仅可以使用自带的 API 来实现最常用的动画,而且通过自定义 View 的方式来做出定制化的动画。

1. ViewPropertyAnimator

使用方式:

View.animate()后跟translationX()等方法,动画会自动执行。

view.animate().translationX(500);

2. ObjectAnimator

使用方式:

如果是自定义控件,需要添加setter/getter方法;

用ObjectAnimator.ofXXX()创建ObjectAnimator对象;

用start()方法执行动画。

public class SportsView extends View {
 float progress = 0; ...... // 创建 getter 方法 public float getProgress() { return progress; } // 创建 setter 方法 public void setProgress(float progress) { this.progress = progress; invalidate(); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); ...... canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint); ...... }}......// 创建 ObjectAnimator 对象ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);// 执行动画animator.start();

3. 通用功能

(1)setDuration(int duration) 设置动画时长

(2)setInterpolator(Interpolator interpolator) 设置 Interpolator(插值器)

AccelerateDecelerateInterpolator 先加速再减速(默认的Interpolator)

LinearInterpolator 匀速

AccelerateInterpolator 持续加速

DecelerateInterpolator 持续减速直到 0

AnticipateInterpolator 先回拉一下再进行正常动画轨迹

OvershootInterpolator 动画会超过目标值一些,然后再弹回来

AnticipateOvershootInterpolator 上面这两个的结合版:开始前回拉,最后超过一些然后回弹

BounceInterpolator 在目标值处弹跳

CycleInterpolator 这个也是一个正弦 / 余弦曲线

FastOutLinearInInterpolator用贝塞尔曲线持续加速

LinearOutSlowInInterpolator 持续减速,初始速度更高

PathInterpolator 自定义动画完成度 / 时间完成度曲线

Path interpolatorPath = new Path();...// 匀速interpolatorPath.lineTo(1, 1);

(3)setListener() / ObjectAnimator.addListener() 设置监听器

参数类型是AnimatorListener,所以本质上其实都是一样的。AnimatorListener共有 4 个回调方法:

onAnimationStart(Animator animation)

onAnimationEnd(Animator animation)

onAnimationCancel(Animator animation)

onAnimationRepeat(Animator animation)

补充:setUpdateListener() /addUpdateListener()

和上面两个方法类似,但是这两个方法虽然名称和可设置的监听器数量不一样,但本质其实都一样的。它们的参数都是AnimatorUpdateListener。它只有一个回调方法:

onAnimationUpdate(ValueAnimator animation)

4.TypeEvaluator

关于 ObjectAnimator,可以用ofInt()来做整数的属性动画和用ofFloat()来做小数的属性动画。这两种属性类型是属性动画最常用的两种,不过在实际的开发中,可以做属性动画的类型还是有其他的一些类型。当需要对其他类型来做属性动画的时候,就需要用到TypeEvaluator了。

(1)ArgbEvaluator

TypeEvaluator最经典的用法是使用ArgbEvaluator来做颜色渐变的动画。

ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);animator.setEvaluator(new ArgbEvaluator());animator.start();

在 Android 5.0 (API 21) 加入了新的方法ofArgb()。

ObjectAnimator animator = ObjectAnimator.ofArgb(view, "color", 0xffff0000, 0xff00ff00);animator.start();

(2)自定义 Evaluator

// 自定义 HslEvaluatorprivate class HsvEvaluator implements TypeEvaluator<Integer> { float[] startHsv = new float[3]; float[] endHsv = new float[3]; float[] outHsv = new float[3]; @Override public Integer evaluate(float fraction, Integer startValue, Integer endValue) { // 把 ARGB 转换成 HSV Color.colorToHSV(startValue, startHsv); Color.colorToHSV(endValue, endHsv); // 计算当前动画完成度(fraction)所对应的颜色值 if (endHsv[0] - startHsv[0] > 180) { endHsv[0] -=360; } else if (endHsv[0] - startHsv[0] < -180) { endHsv[0] =360; } outHsv[0] = startHsv[0] (endHsv[0] - startHsv[0]) * fraction; if (outHsv[0] >360) { outHsv[0] -=360; } else if (outHsv[0] < 0) { outHsv[0] =360; } outHsv[1] = startHsv[1] (endHsv[1] - startHsv[1]) * fraction; outHsv[2] = startHsv[2] (endHsv[2] - startHsv[2]) * fraction; // 计算当前动画完成度(fraction)所对应的透明度 int alpha = startValue >> 24 (int) ((endValue >> 24 - startValue >> 24) * fraction); // 把 HSV 转换回 ARGB 返回 return Color.HSVToColor(alpha, outHsv); }}ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xff00ff00);// 使用自定义的 HslEvaluatoranimator.setEvaluator(new HsvEvaluator());animator.start();

(3)使用不限定类型的属性做动画

借助于TypeEvaluator,属性动画就可以通过ofObject()来对不限定类型的属性做动画了。

1)为目标属性写一个自定义的TypeEvaluator

2)使用ofObject()来创建Animator,并把自定义的TypeEvaluator作为参数填入

private class PointFEvaluator implements TypeEvaluator<PointF> { PointF newPoint = new PointF(); @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { float x = startValue.x (fraction * (endValue.x - startValue.x)); float y = startValue.y (fraction * (endValue.y - startValue.y)); newPoint.set(x, y); return newPoint; }}ObjectAnimator animator = ObjectAnimator.ofObject(view, "position", new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));animator.start();5. PropertyValuesHolder

很多时候,我们需要在同一个动画中改变多个属性,例如在改变透明度的同时改变尺寸。如果使用ViewPropertyAnimator,你可以直接用连写的方式来在一个动画中同时改变多个属性。

view.animate() .scaleX(1) .scaleY(1) .alpha(1);

而对于ObjectAnimator,是不能这么用的。不过你可以使用PropertyValuesHolder来同时在一个动画中改变多个属性。

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)animator.start();

6.AnimatorSet

有的时候,我们不止需要在一个动画中改变多个属性,还会需要多个动画配合工作,比如,在内容的大小从 0 放大到 100% 大小后开始移动。这种情况使用PropertyValuesHolder是不行的,因为这些属性如果放在同一个动画中,需要共享动画的开始时间、结束时间、Interpolator 等一系列的设定,这样就不能有先后次序地执行动画了。这就需要用到AnimatorSet了。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);animator1.setInterpolator(new LinearInterpolator());ObjectAnimator animator2 = ObjectAnimator.ofInt(...);animator2.setInterpolator(new DecelerateInterpolator()); AnimatorSet animatorSet = new AnimatorSet();// 两个动画依次执行animatorSet.playSequentially(animator1, animator2);animatorSet.start();

AnimatorSet还可以这么用:

// 两个动画同时执行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();

7.PropertyValuesHolders.ofKeyframe()

除了合并多个属性和调配多个动画,你还可以在PropertyValuesHolder的基础上更进一步,通过设置Keyframe(关键帧),把同一个动画属性拆分成多个阶段。例如,你可以让一个进度增加到 100% 后再「反弹」回来。

// 在 0% 处开始Keyframe keyframe1 = Keyframe.ofFloat(0, 0);// 时间经过 50% 的时候,动画完成度 100%Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);// 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20%Keyframe keyframe3 = Keyframe.ofFloat(1, 80);PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);animator.start();

总结:「关于复杂的属性关系来做动画」,就这么三种:

使用PropertyValuesHolder来对多个属性同时做动画;

使用AnimatorSet来同时管理调配多个动画;

PropertyValuesHolder的进阶使用:使用PropertyValuesHolder.ofKeyframe()来把一个属性拆分成多段,执行更加精细的属性动画。

点赞

收藏

分享

Fighting_初心发布了37 篇原创文章 · 获赞 38 · 访问量 1万私信 来源:/content-4-622551.html

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。