间时紧张,先记一笔,后续优化与完善。
3.0之前,android支撑两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画统系:property animation,这三种动画模式在SDK中被称为property animation,view animation,drawable animation。
1. View Animation(Tween Animation)
View Animation(Tween Animation):补间动画,给出两个键关帧,通过一些算法将给定性属值在给定的间时内涵两个键关帧间渐变。
View animation只能应用于View象对,而且只支撑一部分性属,如支撑缩放旋转而不支撑背景颜色的转变。
而且对于View animation,它只是转变了View象对制绘的置位,而没有转变View象对本身,比如,你有一个Button,标坐(100,100),Width:200,Height:50,而你有一个动画使其变成Width:100,Height:100,你会发明动画中程过触发钮按点击的区域还是(100,100)-(300,150)。
View Animation就是一系列View外形的换变,如巨细的缩放,明透度的转变,置位的转变,动画的定义既可以用代码定义也可以用XML定义,当然,议建用XML定义。
可以给一个View同时设置多个动画,比如从明透至不明透的淡入效果,与从小到大的放大效果,这些动画可以同时停止,也可以在一个实现后之开始另一个。
用XML定义的动画放在/res/anim/文件夹内,XML文件的根素元可为以<alpha>,<scale>,<translate>,<rotate>,interpolator素元或<set>(示表以上几个动画的集合,set可以嵌套)。认默情况下,全体动画是同时停止的,可以通过startOffset性属设置各个动画的开始移偏(开始间时)来到达动画次序放播的效果。
可以通过设置interpolator性属转变动画渐变的方法,如AccelerateInterpolator,开始时慢,然后渐逐快加。认默为AccelerateDecelerateInterpolator。
定义好动画的XML文件后,可以通过似类面下的代码对指定View应用动画。
ImageView spaceshipImage = (ImageView)findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation=AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
2. Drawable Animation(Frame Animation)
Drawable Animation(Frame Animation):帧动画,就像GIF图片,通过一系列Drawable顺次示显来模拟动画的效果。在XML中的定义方法如下:
1
2
3
4
5
6
|
android:oneshot = "true" > < item android:drawable = "@drawable/rocket_thrust1" android:duration = "200" /> < item android:drawable = "@drawable/rocket_thrust2" android:duration = "200" /> < item android:drawable = "@drawable/rocket_thrust3" android:duration = "200" /> </ animation-list > |
必须以<animation-list>为根素元,以<item>示表要轮换示显的图片,duration性属示表各项示显的间时。XML文件要放在/res/drawable/目录下。示例:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView = (ImageView) findViewById(R.id.imageView1);
imageView.setBackgroundResource(R.drawable.drawable_anim);
anim = (AnimationDrawable) imageView.getBackground();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
anim.stop();
anim.start();
return true;
}
return super.onTouchEvent(event);
}
我在试验中到遇两点问题:
- 要在代码中调用Imageview的setBackgroundResource方法,如果直接在XML局布文件中设置其src性属当触发动画时会FC。
- 在动画start()之前要先stop(),不然在第一次动画后之会停在最后一帧,这样动画就只会触发一次。
- 最后一点是SDK中提到的,不要在onCreate中调用start,因为AnimationDrawable还没有完整跟Window关相联,如果想要界面示显时就开始动画的话,可以在onWindowFoucsChanged()中调用start()。
3. Property Animation
性属动画,这个是在Android 3.0中才引进的,之前学WPF时面里的动画机制似乎就是这个,它变动的是象对的现实性属,在View Animation(Tween Animation)中,其转变的是View的制绘效果,真正的View的性属持保变不,比如无论你在对话中如何缩放Button的巨细,Button的有效点击区域还是没有应用动画时的区域,其置位与巨细都变不。而在Property Animation中,转变的是象对的现实性属,如Button的缩放,Button的置位与巨细性属值都转变了。而且Property Animation不止可以应用于View,还可以应用于任何象对。Property Animation只是示表一个值在一段间时内的转变,当值转变时要做什么事情完整是你自己定决的。
在Property Animation中,可以对动画应用以下性属:
- Duration:动画的持续间时
- TimeInterpolation:性属值的算计方法,如先快后慢
- TypeEvaluator:根据性属的开始、结束值与TimeInterpolation算计出的因子算计出前当间时的性属值
- Repeat Country and behavoir:复重次数与方法,如放播3次、5次、无限环循,可以此动画始终复重,或放播完时再反向放播
- Animation sets:动画集合,即可以同时对一个象对应用几个动画,这些动画可以同时放播也可以对不同动画设置不同开始移偏
- Frame refreash delay:多少间时新刷一次,即每隔多少间时算计一次性属值,认默为10ms,终最新刷间时还受统系进程调度与硬件的影响
3.1 Property Animation的任务方法
对于下图的动画,这个象对的X标坐在40ms内从0动移到40 pixel.按认默的10ms新刷一次,这个象对会动移4次,每次动移40/4=10pixel。
也可以转变性属值的转变方法,即设置不同的interpolation,在下图中动运度速先渐逐增大再渐逐减小
下图示显了与上述动画关相的键关象对
ValueAnimator即示表一个动画,包括动画的开始值,结束值,持续间时等性属。
ValueAnimator装封了一个TimeInterpolator,TimeInterpolator定义了性属值在开始值与结束值之间的插值方法。
ValueAnimator还装封了一个TypeAnimator,根据开始、结束值与TimeIniterpolator算计失掉的值算计出性属值。
ValueAnimator根据动画已停止的间时跟动画总间时(duration)的比算计出一个间时因子(0~1),然后根据TimeInterpolator算计出另一个因子,最后TypeAnimator通过这个因子算计出性属值,如上例中10ms时:
首先算计出间时因子,即经过的间时百分比:t=10ms/40ms=0.25
经插值算计(inteplator)后的插值因子:大约为0.15,上述例子中用了AccelerateDecelerateInterpolator,算计公式为(input即为间时因子):
(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
最后根据TypeEvaluator算计出在10ms时的性属值:0.15*(40-0)=6pixel。上例中TypeEvaluator为FloatEvaluator,算计方法为 :
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
参数分别为上一步的插值因子,开始值与结束值。
3.2 ValueAnimator
ValueAnimator包括Property Animation动画的全体核心功能,如动画间时,开始、结束性属值,响应间时性属值算计方法等。应用Property Animation有两个步聚:
- 算计性属值
- 根据性属值执行响应的动作,如转变象对的某一性属。
ValuAnimiator只实现了第一步任务,如果要实现第二步,要需实现ValueAnimator.onUpdateListener接口,如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("update", ((Float) animation.getAnimatedValue()).toString());
}
});
animation.setInterpolator(new CycleInterpolator(3));
animation.start();
此示例中只是向Logcat输出了一些息信,可为以改想做的任务。
Animator.AnimatorListener
onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel
ValueAnimator.AnimatorUpdateListener
onAnimationUpdate() //通过监听这个件事在性属的值更新时执行响应的操纵,对于ValueAnimator一般要监听此件事执行响应的动作,不然Animation没义意(可用于计时),在ObjectAnimator(承继自ValueAnimator)中会主动更新性属,如无要必不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()获得前当动画性属值。
可以承继AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操纵,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就只用定义想监听的件事而不必实现每一个函数却只定义一空函数体。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.addListener(new AnimatorListenerAdapter(){
public void on AnimationEnd(Animator animation){
Log.i("Animation","end");
}
});
oa.start();
3.3 ObjectAnimator
承继自ValueAnimator,要指定一个象对及该象对的一个性属,当性属值算计实现时主动设置为该象对的响应性属,即实现了Property Animation的全体两步操纵。现实应用中一般都会用ObjectAnimator来转变某一象对的某一性属,但用ObjectAnimator有定一的制约,要想应用ObjectAnimator,该应足满以下条件:
- 象对该应有一个setter函数:set<PropertyName>(驼峰名命法)
- 如上面的例子中,像ofFloat之类的工厂方法,第一个参数为象对名,第二个为性属名,面后的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目标值,性属值的化变围范为前当值到目标值,为了得获前当值,该象对要有响应性属的getter方法:get<PropertyName>
- 如果有getter方法,其应返回值类型应与响应的setter方法的参数类型分歧。
如果上述条件不足满,则不能用ObjectAnimator,应用ValueAnimator替代。
tv=(TextView)findViewById(R.id.textview1);
btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.start();
}
});
把一个TextView的明透度在3秒内从0变至1。
根据应用动画的象对或性属的不同,可能要需在onAnimationUpdate函数中调用invalidate()函数新刷视图。
3.4 通过AnimationSet应用多个动画
AnimationSet供提了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序系关,如同时放播,次序放播等。
以下例子同时应用5个动画:
- 放播anim1;
- 同时放播anim2,anim3,anim4;
- 放播anim5。
1
2
3
4
5
6
|
AnimatorSet bouncer = new AnimatorSet(); bouncer.play(anim1).before(anim2); bouncer.play(anim2).with(anim3); bouncer.play(anim2).with(anim4) bouncer.play(anim5).after(amin2); animatorSet.start(); |
3.5 TypeEvalutors
根据性属的开始、结束值与TimeInterpolation算计出的因子算计出前当间时的性属值,android供提了以下几个evalutor:
- IntEvaluator:性属的值类型为int;
- FloatEvaluator:性属的值类型为float;
- ArgbEvaluator:性属的值类型为十六进制颜色值;
- TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator。
自定义TypeEvalutor很简单,只要需实现一个方法,如FloatEvalutor的定义:
1
2
3
4
5
6
|
public class FloatEvaluator implements TypeEvaluator { public Object evaluate( float fraction, Object startValue, Object endValue) { float startFloat = ((Number) startValue).floatValue(); return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); } } |
根据动画执行的间时跟应用的Interplator,会算计出一个0~1之间的因子,即evalute函数中的fraction参数,通过上述FloatEvaluator该应很好看出其意思。
3.6 TimeInterplator
time interplator定义了性属值化变的方法,如性线平均转变,开始慢然后渐逐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0后之实现代码转移至了TimeInterplator。Interplator承继自TimeInterplator,部内没有任何其他代码。
- AccelerateInterpolator 减速,开始时慢旁边减速
- DecelerateInterpolator 减速,开始时快然后减速
- AccelerateDecelerateInterolator 先减速后减速,开始结束时慢,旁边减速
- AnticipateInterpolator 反向 ,先向相反向方转变一段再减速放播
- AnticipateOvershootInterpolator 反向加超出,先向相反向方转变,再减速放播,会超出目标值然后迟缓动移至目标值
- BounceInterpolator 跃跳,快到目标值时值会跃跳,如目标值100,面后的值可能顺次为85,77,70,80,90,100
- CycleIinterpolator 环循,动画环循定一次数,值的转变成一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
- LinearInterpolator 性线,性线平均转变
- OvershottInterpolator 超出,最后超出目标值然后迟缓转变到目标值
- TimeInterpolator 一个接口,答应你自定义interpolator,以上几个都是实现了这个接口
3.7 当Layout转变时应用动画
ViewGroup中的子素元可以通过setVisibility使其Visible、Invisible或Gone,当有子素元可见性转变时,可以向其应用动画,通过LayoutTransition类应用此类动画:
transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);
通过setAnimator应用动画,第一个参数示表应用的情境,可以以下4种类型:
- APPEARING 当一个素元变成Visible时对其应用的动画
- CHANGE_APPEARING 当一个素元变成Visible时,因统系要新重局布有一些素元要需动移,这些要动移的素元应用的动画
- DISAPPEARING 当一个素元变成InVisible时对其应用的动画
- CHANGE_DISAPPEARING 当一个素元变成Gone时,因统系要新重局布有一些素元要需动移,这些要动移的素元应用的动画 disappearing from the container.
第二个参数为一Animator。
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
此函数设置动画持续间时,参数分别为类型与间时。
3.8 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
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();
3.9 Animating Views
在View Animation中,对View应用Animation并没有转变View的性属,动画的实现是通过其Parent View实现的,在View被drawn时Parents View转变它的制绘参数,draw后再转变参数invalidate,这样虽然View的巨细或旋转角度等转变了,但View的现实性属没变,所以有效区域还是应用动画之前的区域,比如你把一钮按放大两倍,但还是放大这前的区域可以触发点击件事。为了转变这一点,在Android 3.0中给View增加了一些参数并对这些参数增加了响应的getter/setter函数(ObjectAnimator要用这些函数转变这些性属):
- translationX,translationY:换转标坐(control where the View is located as a delta from its left and top coordinates which are set by its layout container.)
- rotation,rotationX,rotationY:旋转,rotation用于2D旋转角度,3D中用到后两个
- scaleX,scaleY:缩放
- x,y:View的终最标坐(utility properties to describe the final location of the View in its container, as a sum of the left and top values and translationX and translationY values.)
- alpha:明透度
//应用动画之前
btn2.getLeft(); //40
btn2.getX(); //40
btn2.getTranslationX(); //0
//应用translationX动画
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2,"translationX", 200);
oa.setDuration(2000);
oa.start();
/*应用translationX动画后
btn2.getLeft(); //40
btn2.getX(); //240
btn2.getTranslationX(); //200
*/
//应用X动画,设假没有应用之前的translationX动画
ObjectAnimator oa=ObjectAnimator.ofFloat(btn2, "x", 200);
oa.setDuration(2000);
oa.start();
/*应用X动画后
btn2.getLeft(); //40
btn2.getX(); //200
btn2.getTranslationX(); //160
*/
case X:
info.mTranslationX = value - mView.mLeft;
break;
Property Animation也可以在XML中定义
- <set> - AnimatorSet
- <animator> - ValueAnimator
- <objectAnimator> - ObjectAnimator
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);
set.setTarget(myObject);
set.start();
3.10 ViewPropertyAnimator
如果要需对一个View的多个性属停止动画可以用ViewPropertyAnimator类,该类对多性属动画停止了优化,合会并一些invalidate()来少减新刷视图,该类在3.1中引入。
以下两段代码实现样同的效果:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
myView.animate().x(50f).y(100f);
文章结束给大家分享下程序员的一些笑话语录:
问路
有一个驾驶热气球的人发现他迷路了。他降低了飞行的高度,并认出了地面 上的一个人。他继续下降高度并对着那个人大叫,“打扰一下,你能告诉我我 在哪吗?”
下面那个人说:“是的。你在热气球里啊,盘旋在 30 英尺的空中”。
热气球上的人说:“你一定是在 IT 部门做技术工作”。
“没错”,地面上的人说到,“你是怎么知道的?”
“呵呵”,热气球上的人说,“你告诉我的每件事在技术上都是对的,但对都没 有用”。
地面上的人说,“你一定是管理层的人”。
“没错”,热气球上的人说,“可是你是怎么知道的?”
“呵呵”,地面上的那人说到,“你不知道你在哪里,你也不知道你要去哪,你 总希望我能帮你。你现在和我们刚见面时还在原来那个地方,但现在却是我 错了”。