Android View动画
2015-06-30 10:48
495 查看
Animation
TypeEvaluator
View的animate方法
ValueAnimator
ObjectAnimator
AnimatorSet
使用xml来创建动画
animation
objectAnimator
set
Animator set
自定义ObjectAnimator属性
propertyValuesHolder
Keyframe
Interpolator
贝塞尔曲线
PathInterpolator
加减速引子
其他的动画常用知识
ValueAnimatorreverse
Android的动画模式:tween animation,frame animation和property animation,又叫View Animation,Drawable Animation和Property Animation,前两种是3.0以前版本支持的,属性动画是3.0以后支持的。
Animation和Animator的区别:Animation只是view的绘制效果,但实际属性没有改变。而Animator改变的是view的属性。比如做位移动画,用Animation时view的实际位置没有改变,而Animator可以改变view的位置。
本文重点介绍属性动画。
比如:
目前系统提供的Evaluator有以下几种:
ArgbEvaluator,FloatArrayEvaluator,FloatEvaluator,IntArrayEvaluator,IntEvaluator,RectEvaluator,PointFEvaluator等,
看ArgbEvaluator的实现,我们发现只需要根据我们定义的属性简单的实现evaluate方法就可以了。这样我们就可以定义自己的XXEvaluator了。
根据动画执行的时间跟应用的Interplator,会计算出一个0~1之间的因子,即evalute函数中的fraction参数。
例子:
下面的例子就实现了一个View的X位移、透明度、缩放的动画
为了实现动画效果,必须为ValueAnimator注册一个监听器ValueAnimator.AnimatorUpdateListener,该监听器负责更新对象的属性值。在实现这个监听器的时候,可以通过getAnimatedValue()的方法来获取当前帧的值。
下面例子用ValueAnimator来实现了一个缩放和位移动画:
下面的例子是用ObjectAnimator来实现X轴位移的动画:
下面的例子用AnimatorSet实现了缩放和位移动画:
关于时间的设置问题:
如果AnimatorSet设置了setDuration,那么不管子动画有没有设置时间,都要AnimatorSet的时间为准,如果AnimatorSet没有设置,那么子动画以各自的时间为准。当所有动画完成后调用onAnimationEnd。
当然也可以用下面的方式做。
test.xml
注意两个R.anim.test不要用错,否则会报错。
通过这个动画也可以看出一般动画和属性动画的区别:
animation做完动画后属性会恢复原样,也就是说它改变的是View的绘制效果,真正的View的属性并没有改变,animator做完动画后保持动画完成时的属性不变,说明它把View的属性改变了。
R.interpolator.test_alpha
Java
test_animator.xml
Java
因为在View中已经实现了alpha属性的动画,那么如果在View中没有实现的属性我们如何使用ObjectAnimator来做动画呢?
我们可以用下面的方法:
test就代表了View的一个属性,只需要一个类继承View并实现
如果用下面这样只为该属性设置一个属性值,那么还要实现getter的方法:
当然如果view中没有该属性的动画,那么还可以用ValueAnimator来实现,只不过要ValueAnimator.AnimatorUpdateListener接口,自己更新相应的属性值
Keyframe类型对象由一个time/value对组成,定义了指定时间点的指定值,即关键帧。
每一个keyframe还可以拥有自己的interpolator,控制了前一个关键帧到这一个关键帧之间的时间动画行为。
Keyframe 对象的构造也用是工厂方法:ofInt(), ofFloat(), or ofObject()。
Keyframe对象构造完之后就可以用 ofKeyframe()工厂方法来构造PropertyValuesHolder对象。
上述代码的意思为:设置btn对象的width属性值使其:
开始时 alpha=1.0
动画开始1/4时 alpha=0.5
动画开始1/2时 alpha=0
动画开始3/4时 alpha=0.5
动画结束时 alpha=1.0
用下面的代码可以实现同样的效果(上述代码时间值是线性,变化均匀):
http://cubic-bezier.com/#.45,0,.21,1
看它的几个构造函数:
public PathInterpolator(Path path) :自定义的Path,但是要保证起点是(0,0),终点是(1,1)。
public PathInterpolator(float controlX, float controlY):二阶的贝塞尔曲线,controlX和controlY是控制点的坐标
public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)三阶的贝塞尔曲线,(controlX1,controlY1)和(controlX2,controlY2)是两个控制点的坐标。
还可以通过xml方式定义PathInterpolator:
enter.xml
用android:pathData来描述一个path
二阶贝塞尔曲线
android:factor 浮点值,加减速速率,默认为1
TypeEvaluator
View的animate方法
ValueAnimator
ObjectAnimator
AnimatorSet
使用xml来创建动画
animation
objectAnimator
set
Animator set
自定义ObjectAnimator属性
propertyValuesHolder
Keyframe
Interpolator
贝塞尔曲线
PathInterpolator
加减速引子
其他的动画常用知识
ValueAnimatorreverse
Android的动画模式:tween animation,frame animation和property animation,又叫View Animation,Drawable Animation和Property Animation,前两种是3.0以前版本支持的,属性动画是3.0以后支持的。
Animation和Animator的区别:Animation只是view的绘制效果,但实际属性没有改变。而Animator改变的是view的属性。比如做位移动画,用Animation时view的实际位置没有改变,而Animator可以改变view的位置。
本文重点介绍属性动画。
1.Animation
用Animation可以实现AlphaAnimation,ScaleAnimation,TranslateAnimation,RotateAnimation。比如:
float fromY = 0f; float toY = 100f; anim = new TranslateAnimation(0.0f, 0.0f, fromY, toY); anim.setInterpolator(new LinearInterpolator()); anim.setDuration(3000); anim.setStartOffset(700); anim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); view.startAnimation(anim);
2. TypeEvaluator
TypeEvaluator提供了一个接口,开发者可以通过实现该接口自定义Evaluator。目前系统提供的Evaluator有以下几种:
ArgbEvaluator,FloatArrayEvaluator,FloatEvaluator,IntArrayEvaluator,IntEvaluator,RectEvaluator,PointFEvaluator等,
看ArgbEvaluator的实现,我们发现只需要根据我们定义的属性简单的实现evaluate方法就可以了。这样我们就可以定义自己的XXEvaluator了。
根据动画执行的时间跟应用的Interplator,会计算出一个0~1之间的因子,即evalute函数中的fraction参数。
public class ArgbEvaluator implements TypeEvaluator { private static final ArgbEvaluator sInstance = new ArgbEvaluator(); public static ArgbEvaluator getInstance() { return sInstance; } public Object evaluate(float fraction, Object startValue, Object endValue) { int startInt = (Integer) startValue; int startA = (startInt >> 24) & 0xff; int startR = (startInt >> 16) & 0xff; int startG = (startInt >> 8) & 0xff; int startB = startInt & 0xff; int endInt = (Integer) endValue; int endA = (endInt >> 24) & 0xff; int endR = (endInt >> 16) & 0xff; int endG = (endInt >> 8) & 0xff; int endB = endInt & 0xff; return (int)((startA + (int)(fraction * (endA - startA))) << 24) | (int)((startR + (int)(fraction * (endR - startR))) << 16) | (int)((startG + (int)(fraction * (endG - startG))) << 8) | (int)((startB + (int)(fraction * (endB - startB)))); } }
例子:
ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(), 0xffffffff, 0xff000000); backgroundColor.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } }); backgroundColor.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int color = (int) animation.getAnimatedValue(); mView.setBackgroundColor(color); } }); backgroundColor.setInterpolator(new LinearInterpolator()); backgroundColor.setDuration(500); backgroundColor.start();
3. View的animate()方法
我们也可以直接使用View的API animate()来做动画,而且还可以几个动画同时做哦!下面的例子就实现了一个View的X位移、透明度、缩放的动画
view.animate().translationX(animTranslationXPx) .alpha(0.5f) .setStartDelay(0) .scaleX(0.8f) .scaleY(0.8f) .setUpdateListener(null) .setInterpolator(new AccelerateDecelerateInterpolator()) .setDuration(1000) .withEndAction(new Runnable() { @Override public void run() { } }) .start();
4. ValueAnimator
ValueAnimator就是一个数值产生器,他本身不作用于任何一个对象,但是可以对产生的值进行动画处理。为了实现动画效果,必须为ValueAnimator注册一个监听器ValueAnimator.AnimatorUpdateListener,该监听器负责更新对象的属性值。在实现这个监听器的时候,可以通过getAnimatedValue()的方法来获取当前帧的值。
下面例子用ValueAnimator来实现了一个缩放和位移动画:
final Rect fromRect = ...... final Rect toRect = ...... final float originScaleX = 1.0f;//(float)fromRect.width() / toRect.width(); final float originScaleY = 1.0f;//(float)fromRect.height() / toRect.height(); ValueAnimator trans = ValueAnimator.ofFloat(0, 1); trans.setInterpolator(new LinearInterpolator()); trans.setDuration(600); trans.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } }); trans.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = (Float)animation.getAnimatedValue(); float toX = (fromRect.left + percent * (toRect.left - fromRect.left)); float toY = (fromRect.top + percent * (toRect.top - fromRect.top)); float toR = (fromRect.right + percent * (toRect.right - fromRect.right)); float toB = (fromRect.bottom + percent * (toRect.bottom - fromRect.bottom)); float scaleX = (float)(toR - toX) / fromRect.width(); float scaleY = (float)(toB - toY) / fromRect.height(); view.setTranslationX(toX-view.getLeft()); view.setTranslationY(toY-view.getTop()); view.setScaleX(scaleX*originScaleX); view.setScaleY(scaleY*originScaleY); float alpha = 0 + percent * 1 / (0.8f - 0); ...... } }); trans.start();
5. ObjectAnimator
ObjectAnimator继承自ValueAnimator,它会自动更新我们定义的属性值,来实现动画的目的。下面的例子是用ObjectAnimator来实现X轴位移的动画:
ObjectAnimator anim = ObjectAnimator.ofFloat(v,View.TRANSLATION_X, newPos); anim.setInterpolator(new LinearInterpolator()); anim.setDuration(500); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } }); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { } }); anim.start();
6. AnimatorSet
AnimatorSet用于实现多个动画的协同作用,AnimatorSet中有一系列的顺序控制方法:playTogether、playSequentially、animSet.play().with()、defore()、after()等。用来实现多个动画的协同工作方式。下面的例子用AnimatorSet实现了缩放和位移动画:
ObjectAnimator trans = ObjectAnimator.ofFloat(view,View.TRANSLATION_X, newPos); ObjectAnimator scalex = ObjectAnimator.ofFloat(view, View.SCALE_X, 1.0f, 0.8f); ObjectAnimator scaley = ObjectAnimator.ofFloat(view, View.SCALE_Y, 1.0f, 0.8f); AnimatorSet animSet = new AnimatorSet(); animSet.playTogether(scalex, scaley, trans); animSet.setDuration(duration); animSet.setInterpolator(new LinearInterpolator()); animSet.addListener(new AnimatorListener() { @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { // do end; } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationStart(Animator animation) { } }); animSet.start();
关于时间的设置问题:
如果AnimatorSet设置了setDuration,那么不管子动画有没有设置时间,都要AnimatorSet的时间为准,如果AnimatorSet没有设置,那么子动画以各自的时间为准。当所有动画完成后调用onAnimationEnd。
7.使用xml来创建动画
animation
final Animation ani = AnimationUtils.loadAnimation(this, R.anim.test); ani.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); mView.startAnimation(ani);
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromXScale="1.0" android:toXScale="0.2" android:fromYScale="1.0" android:toYScale="1.0" />
当然也可以用下面的方式做。
objectAnimator
Animator ani= AnimatorInflater.loadAnimator(this, R.anim.test); ani.setTarget(mView); ani.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } }); ani.start();
test.xml
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="0.2" android:valueType="floatType" > </objectAnimator>
注意两个R.anim.test不要用错,否则会报错。
通过这个动画也可以看出一般动画和属性动画的区别:
animation做完动画后属性会恢复原样,也就是说它改变的是View的绘制效果,真正的View的属性并没有改变,animator做完动画后保持动画完成时的属性不变,说明它把View的属性改变了。
set
R.anim.test<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:interpolator="@interpolator/test_alpha" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:duration="336"/> <translate android:fromYDelta="15%" android:toYDelta="0" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" android:interpolator="@interpolator/test_translate" android:duration="336"/> <scale android:fromXScale="0.94" android:toXScale="1.0" android:fromYScale="0.94" android:toYScale="1.0" android:interpolator="@interpolator/test_scale" android:duration="336" android:pivotX="50%" android:pivotY="50%"/> </set>
R.interpolator.test_alpha
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.1" android:controlY1="0" android:controlX2="0" android:controlY2="1" />
Java
final Animation ani = AnimationUtils.loadAnimation(mActivity, R.anim.test); ani.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } }); imageView.startAnimation(ani);
Animator set
当然也可以用下面的方式实现:test_animator.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" android:shareInterpolator="false" android:zAdjustment="top"> <objectAnimator android:propertyName="alpha" android:valueFrom="0.0" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_alpha" android:duration="336" /> <objectAnimator android:propertyName="translationY" android:valueFrom="@dimen/translation_y" android:valueTo="0" android:valueType="floatType" android:interpolator="@interpolator/test_alpha" android:duration="336" /> <set android:ordering="together"> <objectAnimator android:propertyName="scaleX" android:valueFrom="0.94" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_scale" android:duration="336" /> <objectAnimator android:propertyName="scaleY" android:valueFrom="0.94" android:valueTo="1.0" android:valueType="floatType" android:interpolator="@interpolator/test_scale" android:duration="336" /> </set> </set>
Java
Animator animator = AnimatorInflater.loadAnimator(mActivity, R.animator.test_animator); animator.setTarget(view); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { end.run(); } @Override public void onAnimationCancel(Animator animation) { end.run(); } @Override public void onAnimationRepeat(Animator animation) { } }); animator.start();
8.自定义ObjectAnimator属性
通常情况下我们使用ObjectAnimator来实现动画效果,可以用下面的方法:ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f); anim.setDuration(1000); anim.start();
因为在View中已经实现了alpha属性的动画,那么如果在View中没有实现的属性我们如何使用ObjectAnimator来做动画呢?
我们可以用下面的方法:
ObjectAnimator anim = ObjectAnimator.ofFloat(myTextView, "test", 0f, 1f); anim.setDuration(1000); anim.start();
test就代表了View的一个属性,只需要一个类继承View并实现
public void setTest(float set){ //to do something }
如果用下面这样只为该属性设置一个属性值,那么还要实现getter的方法:
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "testt", 1f); anim.setDuration(1000); anim.start(); public void setTestt(float set){ mTestt = set; } public float getTestt(){ return mTestt; }
当然如果view中没有该属性的动画,那么还可以用ValueAnimator来实现,只不过要ValueAnimator.AnimatorUpdateListener接口,自己更新相应的属性值
9.propertyValuesHolder
多动画效果的另一种实现方法PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f); ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ) .setDuration(1000) .start();
10.Keyframe
PropertyValuesHolder的工厂方法里面,除了整形ofInt()、浮点型ofFloat()、Object类型ofObject()之外,还有一种:ofKeyframe()。Keyframe类型对象由一个time/value对组成,定义了指定时间点的指定值,即关键帧。
每一个keyframe还可以拥有自己的interpolator,控制了前一个关键帧到这一个关键帧之间的时间动画行为。
Keyframe 对象的构造也用是工厂方法:ofInt(), ofFloat(), or ofObject()。
Keyframe对象构造完之后就可以用 ofKeyframe()工厂方法来构造PropertyValuesHolder对象。
Keyframe kf0 = Keyframe.ofFloat(0, 1.0f); Keyframe kf1 = Keyframe.ofFloat(0.25f, 0.5f); Keyframe kf2 = Keyframe.ofFloat(0.5f, 0f); Keyframe kf4 = Keyframe.ofFloat(0.75f, 0.5f); Keyframe kf3 = Keyframe.ofFloat(1f, 1.0f); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2, kf4, kf3); ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(mView, pvhRotation); anim.setDuration(2000); anim.start();
上述代码的意思为:设置btn对象的width属性值使其:
开始时 alpha=1.0
动画开始1/4时 alpha=0.5
动画开始1/2时 alpha=0
动画开始3/4时 alpha=0.5
动画结束时 alpha=1.0
用下面的代码可以实现同样的效果(上述代码时间值是线性,变化均匀):
ObjectAnimator oa=ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.5f, 0f, 0.5f, 1.0f); oa.setDuration(2000); oa.start();
11.Interpolator
贝塞尔曲线
一个查看三阶贝塞尔曲线效果的网站http://cubic-bezier.com/#.45,0,.21,1
PathInterpolator
PathInterpolator是android5.0才开始提供的一种时间时间插值器,和LinearInterpolator,AccelerateDecelerateInterpolator一样用来设置给animator或者animation的,PathInterpolator需要一段起点是(0,0),终点是(1,1)的path路径。看它的几个构造函数:
public PathInterpolator(Path path) :自定义的Path,但是要保证起点是(0,0),终点是(1,1)。
public PathInterpolator(float controlX, float controlY):二阶的贝塞尔曲线,controlX和controlY是控制点的坐标
public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)三阶的贝塞尔曲线,(controlX1,controlY1)和(controlX2,controlY2)是两个控制点的坐标。
还可以通过xml方式定义PathInterpolator:
...... ValueAnimator trans = ValueAnimator.ofFloat(0, 1); trans.setInterpolator(enterInterpolator); ...... public Interpolator enterInterpolator; enterInterpolator= AnimationUtils.loadInterpolator(context,R.interpolator.enter);
enter.xml
<?xml version="1.0" encoding="utf-8"?> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.45" android:controlY1="0" android:controlX2="0.34" android:controlY2="1" />
用android:pathData来描述一个path
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="L0.3,0 C 0.5,0 0.7,1 1, 1" />
二阶贝塞尔曲线
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:controlX1="0.3" android:controlY1="0"/>
加减速引子
<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:factor="2.5" />
android:factor 浮点值,加减速速率,默认为1
其他的动画常用知识:
ValueAnimator.reverse()
反向进行当前的ValueAnimator动画,可以进行取消动画时的动画,当动画已经开始运行时,调用reverse(),那么当前动画会停止,并从当前动画的点反向进行已经做过的动画。如果动画还没有开始,那么他会从最后开始向前做动画。相关文章推荐
- Android-RecyclerView-Item点击事件设置
- android 与javascipt 之间相互调用
- 为自己记----android中关于actionbar的一些简单理解
- Android Web 应用开发详解
- android 自动登录和记住密码
- android 反编译
- PHP后台2:客户端(IOS/Android)Post请求以及JSON数据编解码
- android-service的简单用法
- android studio 开发 gradle 详解(五)
- android-percent-support-lib-sample
- 百度经验:常用的Android.mk变量解释
- Android系统版本与API Level对照表
- Android中动态生成ListView及SimpleAdapter的使用
- Android studio ElasticDownloadView
- android 适配器的使用
- 完整的Android源码截屏事件的捕获--5.0
- android 中 EditText加入图标 更改边框颜色 设置透明
- android 自定义适配器BaseAdapter
- Android Drawable
- Android下拉列表Spinner