文章的知识借鉴了很多其他大神的内容,梳理了很久,有些内容已经忘记文章的衔接了,这里对原作者说声抱歉了。
本篇文章介绍的都是Android 的基础内容,很多是老生常谈了,不过我总结了自己经历的一些项目,与学习中遇到的一些有代表性的内容,写了一个Android动画工程,基本可以与下面介绍的内容对照起来,感兴趣的可以下载下来对照观看,会更容易理解。
Android 系统提供了三种动画:View animation 、 Frame animation 、Property animation
一,View animation
View animation 视图动画,也称作(Tween)补间动画,是一种渐进式动画,通过图像的平移、缩放、旋转和透明度等渐进方式完成动画效果。特别注意:补间动画执行之后其实并没有真正改变View的属性,即left、top、right和bottom的值,只是系统临时绘制的结果。View动画也有一些特殊的使用场景,如LayoutAnimation,以及Actiivty切换的效果。
1.Animation
xml属性 | java方法 | 意义 |
android:detachWallpaper | setDetachWallpaper(boolean) | 是否在壁纸上运行 |
android:duration | setDuration(long) | 动画持续时间,毫秒为单位 |
android:fillAfter | setFillAfter(boolean) | 动画结束是否保持最后的状态 |
android:fillBefore | setFillBefore(boolean) | 动画结束是否还原开始的状态 |
android:fillEnabled | setFillEnabled(boolean) | 与android:fillBefore效果相同 |
android:interpolator | setInterpolator(Interpolator) | 设定插值器(指定的动画效果,譬如回弹、匀速等) |
android:repeatCount | setRepeatCount(int) | 重复次数 |
android:repeatMode | setRepeatMode(int) | 重复类型有两个值,reverse表示倒序回放,restart表示从头播放 |
android:startOffset | setStartOffset(long) | 调用start函数之后等待开始运行的时间,单位为毫秒 |
android:zAdjustment | setZAdjustment(int) | 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal |
| reset() | 重置Animation的初始化 |
| cancel() | 取消Animation动画 |
| start() | 开始Animation动画 |
| setAnimationListener(AnimationListener listener) | 设置动画监听 |
| hasStarted() | 判断当前Animation是否开始 |
| hasEnded() | 判断当前Animation是否结束 |
2.AlphaAnimation 渐变透明度
xml属性 | java方法 | 意义 |
android:fromAlpha | AlphaAnimation(float fromAlpha, …) | 动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明) |
android:toAlpha | AlphaAnimation(…, float toAlpha) | 动画结束的透明度,同上 |
3.RotateAnimation 旋转动画
xml属性 | java方法 | 意义 |
android:fromDegrees | RotateAnimation(float fromDegrees, …) | 旋转开始角度,正代表顺时针度数,负代表逆时针度数 |
android:toDegrees | RotateAnimation(…, float toDegrees, …) | 旋转结束角度,正代表顺时针度数,负代表逆时针度数 |
android:pivotX | RotateAnimation(…, float pivotX, …) | 起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY | RotateAnimation(…, float pivotY) | 起点Y坐标,同上规律 |
4.ScaleAnimation 渐变伸缩动画
xml属性 | java方法 | 意义 |
android:fromXScale | ScaleAnimation(float fromX, …) | 初始X轴缩放比例,1.0表示无变化 |
android:toXScale | ScaleAnimation(…, float toX, …) | 结束X轴缩放比例 |
android:fromYScale | ScaleAnimation(…, float fromY, …) | 初始Y轴缩放比例 |
android:toYScale | ScaleAnimation(…, float toY, …) | 结束Y轴缩放比例 |
android:pivotX | ScaleAnimation(…, float pivotX, …) | 起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:pivotY | ScaleAnimation(…, float pivotY) | 起点Y轴坐标,同上规律 |
5. TranslateAnimation 位置移动动画
xml属性 | java方法 | 意义 |
android:fromXDelta | TranslateAnimation(float fromXDelta, …) | 起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点) |
android:fromYDelta | TranslateAnimation(…, float fromYDelta, …) | 起始点Y轴从标,同上规律 |
android:toXDelta | TranslateAnimation(…, float toXDelta, …) | 结束点X轴坐标,同上规律 |
android:toYDelta | TranslateAnimation(…, float toYDelta) | 结束点Y轴坐标,同上规律 |
6. LayoutAnimation 布局动画,作用于ViewGroup,为ViewGroup指定一个动画,它的子元素出场时都具有这种动画效果,初始化的时候触发。
有两种设置方式,一种直接在xml中设置,一种在代码中通过LayoutAnimationController来设置,具体内容可以查看项目实例。
xml属性 | java方法 | 意义 |
android:delay | setDelay(folat) | 子元素开始动画延迟的时间 |
android:animationOrder | setOrder() | normal(顺序显示)、reverse(逆向显示),random(随机显示) |
7. Activity切换效果
Activity有默认的切换效果,也可以自定义切换效果,主要是使用overridePendingTransition(int enterAnim, int exitAnim),这个方法必须在startActiivty()或者finis()之后调用才有效。fragment(api11)可以添加切换动画,兼容使用FragmentTransition的setCustomAnimation添加切换动画,必须是View动画,兼容和适配的问题。具体内容可以查看项目实例。
8.AnimationSet 继承Animation,可以持有AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation等动画的容器。
| Animation(boolean) | true,共享插值器设定效果;flase,各自使用自身插拔器 |
9.Interpolator 插值器,指定动画效果
java类 | xml id值 | 描述 |
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 动画始末速率较慢,中间加速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 动画开始速率较慢,之后慢慢加速 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 开始的时候从后向前甩 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 类似上面AnticipateInterpolator |
BounceInterpolator | @android:anim/bounce_interpolator | 动画结束时弹起 |
CycleInterpolator | @android:anim/cycle_interpolator | 循环播放速率改变为正弦曲线 |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 动画开始快然后慢 |
LinearInterpolator | @android:anim/linear_interpolator | 动画匀速改变 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 向前弹出一定值之后回到原来位置 |
PathInterpolator | | 新增,定义路径坐标后按照路径坐标来跑。 |
ShareInterpolator | android:shareInterpolator=“boolean” | set标签中有多个动画,共享时为true;不共享,在每个动画中添加 |
10. 自定义动画,如Rotate3dAnimation
自定义需要继承Animation,并重新applyTransformation(float interpolatedTime,Transformation t)方法和initalize(int width ,int height ,int parentWidth ,int parentHeight)方法。
a. interpolatedTime 代表了时间的进行程度,如设置时间1000ms,数值是0-—1,1表示动画结束;Transformation 代表补间动画在不同时刻对图形或控件的变形程度。该对象封装了一个Matrix对象,可以对它进行位移、倾斜、旋转等变换,Transformation将对应的图片或资源进行相应的变换。
b. initalize(…)函数,这是一个回调函数,告诉Animation目标View 的大小参数,在这里可以初始化一些相关参数,如动画执行时间、Interpolator等等。
为了控制图片或View进行三维空间的变换,还需要借助于一个Camera类,这是一个3d空间变换工具,作用类似于Matrix,有如下常用方法:
getMatrix(Matrix matrix):将Camera所做的变换应用到指定的matrix上。
rotateX(float deg)、rotateY(float deg)、rotateZ(float deg):将目标控件沿X/Y/Z轴旋转。
translate(float x,float y,float z):目标控件在三维空间进行位移变换。
applyToCanvas(Canvas canvas):把Camera所做的变换应用到Canvas上。
Camera类坐标系可以参考 http://www.jianshu.com/p/34e0fe5f9e31
二,Frame animation
Frame animation 帧动画,通过不停的切换图片实现动画效果,比较容易OOM,注意图片大小和资源回收。
<animation-list>必须是根节点,包含一个或多个<item>元素,android:oneshot =“boolean”,true代表执行一次,false表示循环执行。在<item>元素中,android:drawable 表示Drawable资源,android:duration执行时间。
三,Property animation
Property animation 属性动画 ,通过不停的改变对象的属性实现动画效果,如平移translationX/Y、缩放scaleX/Y、旋转rotationX/Y等并刷新屏幕来实现动画效果,并且实现点击位置的实时改变。在实际开发中建议采用代码来实现属性动画,比较简单,更重要的是,很多时候一个属性的起始值是无法确认的。
java类 | xml id值 | 描述 |
AnimatorSet | <set> | |
ValueAnimator | <animator> | |
ObjectAnimator | <objectAnimator> | |
| android:ordering | “together”表示动画集合中的子动画一起播放;“sequentially”集合动画按照前后顺序播放,默认是together |
1. ValueAnimator
在一个特定的时间内执行一个动画,继承于ValueAnimator它没有直接操作属性值的逻辑,需要添加动画更新的监听,并在onAnimationUpdater()中执行自定义的动画逻辑。
ValueAnimator mAnimator =ValueAnimator.ofInt(1,100);
2. TimeAnimator
时序监听会掉工具,是在api16引入,不能直接实现动画效果,在监听方法TimeListener中返回动画持续的时间,逻辑也需要自己添加。
一个对象的一个属性动画, 继承于ValueAnimator,允许你指定要进行动画的对象以及该对象 的一个属性。该类会根据计算得到的新值自动更新属性。多数场景下采用的就是ObjectAnimator。
ObjectAnimator类提供了ofInt、ofFloat、ofObject这个三个常用的方法,这些方法都是设置动画作用的元素、属性、开始、结束等任意属性值。当属性值(上面方法的参数)只设置一个时就把通过getXXX反射获取的值作为起点,设置的值作为终点;如果设置两个(参数),那么一个是开始、另一个是结束。
特别注意:ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值,所有使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法。
我们通常使用ObjectAnimator设置View已知的属性来生成动画,而一般View已知属性变化时都会主动触发重绘图操作,所以动画会自 动实现;但是也有特殊情况,譬如作用Object不是View,或者作用的属性没有触发重绘,或者我们在重绘时需要做自己的操作
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(View view,String propertyName,float... values);
view 表示动画的对象
propertyName 作用对象的属性名称,如translationX/Y,scaleX/Y
float... values 一个集合的时间值,一般为两个值,开始、结束,有propertyName决定其意义,如果指定属性表示的是颜色,就不需要指定valueType.
xml属性 | java方法 | 意义 |
android:propertyName | ObjectAnimator.ofFloat(…,String propertyName,…) | String类型,必须要设置的节点属性,代表要执行动画的属性(通过名字引用),辟如你可以指定了一个View的”alpha” 或者 “backgroundColor” ,这个objectAnimator元素没有对外说明target属性,所以你不能在XML中设置执行这个动画,必须通过调用 loadAnimator()方法加载你的XML动画资源,然后调用setTarget()应用到具备这个属性的目标对象上(譬如TextView) |
android:valueFrom | ObjectAnimator.ofFloat(…,…,float startValue,…) | 相对应valueTo,动画的起始点,如果没有指定,系统会通过属性的get方法获取,颜色也是6位十六进制的数字表示。 |
android:valueTo | ObjectAnimator.ofFloat(…,…,,…,float endValue) | float、int或者color类型,必须要设置的节点属性,表明动画结束的点;如果是颜色的话,由6位十六进制的数字表示。 |
android:repeatCount | setRepeatCount(int) | 重复次数,-1表示无限循环,默认0 |
android:repeatMode | setRepeatMode(int) | 重复类型有两个值,reverse表示倒序回放,restart表示从头播放 |
android:startOffset | setStartDelay(long startDelay) | 调用start函数之后等待开始运行的时间,单位为毫秒 |
android:valueType | ofFloat,ofInt | 指定属性的类型,关键参数,如果该value是一个颜色,那么就不需要指定,因为动画框架会自动的处理颜色值。有intType和floatType(默认)两种:分别说明动画值为int和float型。 |
4. PropertyValuesHolder 多属性动画同时工作管理类(适合在同一个Vie对象)
PropertyValuesHolder a1 =PropertyValuesHolder.ofFloat(“alpha”,0,1f);
PropertyValuesHolder a2 =PropertyValuesHolder.ofFloat(“translationY”,0,1f);
ObjectAnimator.ofPropertyValuesHolder(view,a1,a2,…).setDuration(100).start();
5. AnimatorSet 动画集合,相对于PropertyValuesHolder,AnimatorSet适合多个或单个View,可以设置动画执行的顺序,类似与View 动画中的AnimationSet。
java方法 | |
play | 执行 |
with | 同时执行 |
after | 在指定的动画之后执行 |
before | 在指定的动画之前执行 |
playTogether | 同时执行 |
playSequentially | 顺序播放 |
6. 属性动画计算原理
a.Interpolator 插值器
AccelerateDecelerateInterolator:先加速后减速。
AccelerateInterpolator:加速。
DecelerateInterpolator:减速。
AnticipateInterpolator:先向相反方向改变一段再加速播放。
AnticipateOvershootInterpolator:先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹。
BounceInterpolator:快到目标值时值会跳跃。
CycleIinterpolator:动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)。
LinearInterpolator:线性均匀改变。
OvershottInterpolator:最后超出目标值然后缓慢改变到目标值。
TimeInterpolator 时间插值器 ,一个允许自定义Interpolator的接口,以上都实现了该接口,根据时间流失的百分比来计算出当前属性值改变的百分比。
b.Evaluator 类型估值器
Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。
IntEvaluator:整数属性值。
FloatEvaluator:浮点数属性值。
ArgbEvaluator:十六进制color属性值。
TypeEvaluator:用户自定义属性值接口,譬如对象属性值类型不是int、float、color类型,你必须实现这个接口去定义自己的数据类型。
根据当前属性改变的百分比来计算改变后的属性值,系统预设的有属性动画中的插值器和估值器是实现非匀速动画的重要条件。
更具体的内容可以参照:http://www.cnblogs.com/huolongluo/p/6523552.html
7.ViewPropertyAnimator
其一:我们在一个没有内建「属性概念」的语言中做属性动画。由于系统运行时对「属性」没概念,因此 ObjectAnimator 需要通过特殊手段把「代表属性名称的字符串」变成对「目标对象属性的 setter 方法」的调用。比如遇到字符串 "alpha" 就知道该去调用 View.setAlpha()。这种间接手段被称为反射 reflection 或者 JNI(java native interface),虽然可靠但会带来额外开销。基于对视图属性的了解,我们应该提供一些 API 使得动画可以直接操作属性,避开这种间接手段。
其二:有些情景中可能需要同时对一个 View 的多个属性做动画。虽然所有动画共享计时机制而不会因计时产生额外开销,但多个属性动画需要构造多个 Animator 对象。既然我们知道要对 View 的哪几个属性做动画,就应该考虑将多个动画合并成一个,以减少开销。一种方法是使用 PropertyValuesHolder,它允许仅构造一个 Animator 对象,就可以实现多个属性动画。但这种方法需要更多的代码,对简单的动画而言过于笨重。应该有一种新的方法既能实现我们的期望,同时代码也是简单易读的。
其三:View 的每一个属性都会执行一些操作以确保视图对象及其父对象在合适的时候重绘。比如, 在 x 轴平移视图,会使视图过去和现在的位置失效,以确保父视图正确地重绘它。而在 y 轴平移视图,也会做类似的操作。如果这两个属性同时改变,还做双份的重绘工作就显得多余。所以应该将这些工作合并在一起。ViewPropertyAnimator 可以做到
ViewPropertyAnimator 提供了一种并行属性动画的简单方法。只需构建一个 Animator(译注:针对上述2);能够直接修改目标视图的属性值(译注:针对上述1);优化重绘工作,使多个属性的重绘仅发生一次(译注:针对上述3)
一个简单的例子:
AnimatorSet
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
PropertyValuesHolder
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator(api12)
ViewPropertyAnimator viewPropertyAnimator =mCloud.animate();
viewPropertyAnimator.x(50f).y(100f);
或者mCloud.animate().x(50f).y(100f);
animate():从调用 View 对象的 animate() 方法开始,该方法返回一个 ViewPropertyAnimator 实例,然后就可以调用它的方法来设置动画参数。
自动开始:要注意上述两行代码并未调用 start() 方法,因为在新 API 中动画启动是隐式的,一旦声明完,这些动画就「立刻」「一起」启动了。如果要深究细节的话,其实也并非「立刻」启动,而是在下一次 UI 刷新时。ViewPropertyAnimator 正是利用了这个时间差,把所有声明的动画收集在一起。只要还在继续声明新的动画,那么所有动画就会继续等待下一次 UI 刷新。一旦完成声明,所有动画就在下一次 UI 刷新时一起启动了。
流式接口:ViewPropertyAnimator 拥有流式接口(Fluent interface),允许函数链式调用,使得在一行代码中可以构建多个属性动画。
更具体的内容可以参照:https://segmentfault.com/a/1190000004411201
8. LayoutTransition 容器布局动画
LayoutTransition对 ViewGroup中的View进行动画设置显示。LayoutTransition的动画效果都是设置给ViewGroup,然后当被设置动画的 ViewGroup中添加删除View时体现出来。该类用于当前布局容器中有View添加、删除、隐藏、显示等时候定义布局容器自身的动画和View的动 画,也就是说当在一个LinerLayout中隐藏一个View的时候,我们可以自定义 整个由于LinerLayout隐藏View而改变的动画,同时还可以自定义被隐藏的View自己消失时候的动画等。
LayoutTransition类中主要有五种容器转换动画类型
• LayoutTransition.APPEARING:当View出现或者添加的时候View出现的动画。
• LayoutTransition.CHANGE_APPEARING:当添加View导致布局容器改变的时候整个布局容器的动画。
• LayoutTransition.DISAPPEARING:当View消失或者隐藏的时候View消失的动画。
• LayoutTransition.CHANGE_DISAPPEARING:当删除或者隐藏View导致布局容器改变的时候整个布局容器的动画。
• LayoutTransition.CHANGE:当不是由于View出现或消失造成对其他View位置造成改变的时候整个布局容器的动画。
我们可以通过如下方式使用系统提供的默认ViewGroup的LayoutTransition动画:android:animateLayoutChanges=”true”
在ViewGroup添加如上xml属性默认是没有任何动画效果的,因为前面说了,该动画针对于ViewGroup内部东东发生改变时才有效,所以当我们设置如上属性然后调运ViewGroup的addView、removeView方法时就能看见系统默认的动画效果了。
还有一种就是通过如下方式设置: android:layoutAnimation=”@anim/customer_anim”
在使用LayoutTransition时,你可以自定义这几种事件类型的动画,也可以使用默认的动画,总之最终都是通过 setLayoutTransition(LayoutTransition lt)方法把这些动画以一个LayoutTransition对象设置给一个ViewGroup。譬如实现如上Xml方式的默认系统LayoutTransition动画如下:
LayoutTransition mTransitioner = new LayoutTransition();
mViewGroup.setLayoutTransition(mTransitioner);
稍微再高端一点吧,我们来自定义这几类事件的动画,分别实现他们,那么你可以像下面这么处理:
mTransitioner = new LayoutTransition();
......
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "scaleX", 0, 1);
......//设置更多动画
mTransition.setAnimator(LayoutTransition.APPEARING, anim);
......//设置更多类型的动画
mViewGroup.setLayoutTransition(mTransitioner);
9.Keyframes
keyFrame是一个 时间/值 对,通过它可以定义一个在特定时间的特定状态,而且在两个keyFrame之间可以定义不同的Interpolator,就相当多个动画的拼接,第一个动画的结束点是第二个动画的开始点。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如以下例子:
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);
rotationAnim.setDuration(2000);
上述代码的意思为:设置btn对象的width属性值使其:
开始时 Width=400
动画开始1/4时 Width=200
动画开始1/2时 Width=400
动画开始3/4时 Width=100
动画结束时 Width=500
第一个参数为时间百分比,第二个参数是在第一个参数的时间时的属性值。
定义了一些Keyframe后,通过PropertyValuesHolder类的方法ofKeyframe封装,然后通过ObjectAnimator.ofPropertyValuesHolder获得Animator。
用下面的代码可以实现同样的效果:
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();
=====================================
Android Animation 项目地址:https://github.com/xianjuren/AndroidAnimation