android动画总结
android动画大致可以分为两类,一类是通过播放多张图片的帧动画,另一类就是通过设置和修改控件属性达到动画的目的。
帧动画
1、通过xml文件设置帧动画
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/run1"
android:duration="100"/>
<item
android:drawable="@drawable/run2"
android:duration="100"/>
<item
android:drawable="@drawable/run3"
android:duration="100"/>
<item
android:drawable="@drawable/run4"
android:duration="100"/>
<item
android:drawable="@drawable/run5"
android:duration="100"/>
<item
android:drawable="@drawable/run6"
android:duration="100"/>
<item
android:drawable="@drawable/run7"
android:duration="100"/>
</animation-list>
2.通过代码设置帧动画:
AnimationDrawable animationDrawable = new AnimationDrawable();
for (int i = 1; i < 8; i++) {
int id = getResources().getIdentifier("run" + i, "drawable", getPackageName());
Drawable drawable = getDrawable(id);
if (null != drawable) {
animationDrawable.addFrame(drawable, 100);
}
}
3.启动和结束动画:
1、xml形式
AnimationDrawable animationDrawable = (AnimationDrawable) target.getDrawable();
2、代码形式:
target.setImageDrawable(animationDrawable);
3、开始/停止动画
target.start();/target.stop();
属性动画
属性动画主要围绕几个属性进行,旋转、平移、缩放、透明度,通过设置初始值和最终值根据给定的时间和加速曲线进行,xml展现如下:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:shareInterpolator="true">
<alpha
android:duration="2000"
android:fillAfter="true"
android:fillBefore="false"
android:fromAlpha="1.0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toAlpha="0.0"/>
<rotate
android:duration="2000"
android:fillAfter="true"
android:fillBefore="false"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:toDegrees="360"/>
<set
android:interpolator="@android:anim/bounce_interpolator"
android:shareInterpolator="true"
android:startOffset="1000">
<scale
android:duration="2000"
android:fillAfter="true"
android:fillBefore="false"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="2"
android:repeatMode="reverse"
android:toXScale="2.0"
android:toYScale="2.0"/>
<translate
android:duration="2000"
android:fillAfter="true"
android:fillBefore="false"
android:fromXDelta="0"
android:fromYDelta="0"
android:repeatCount="2"
android:repeatMode="reverse"
android:toXDelta="200%"
android:toYDelta="200%"/>
</set>
</set>
fromXDelta: X轴方向开始位置,可以是%,也可以是具体的像素
fromYDelta: Y轴方向开始位置,可以是%,也可以是具体的像素
toXDelta:X轴方向结束位置,可以是%,也可以是具体的像素
toYDelta:Y轴方向结束位置,可以是%,也可以是具体的像素
pivotX:表示缩放/旋转起点 X 轴坐标,可以是整数值、百分数(或者小数)、百分数p三种样式,比如 50、50% / 0.5、50%p。当属性值为数值时,表示在当前 View 的左上角,即原点处加上 50px,作为起始点;如果是百分数,比如 50%,表示在当前控件的左上角加上自己宽度的 50% (即自身宽度中心)作为起始点;如果是 50%p(字母 p 是 parent 的意思),取值的基数是父控件,那么 50%p 就是表示在当前的左上角加上父控件宽度的 50% 作为起始点 x 轴坐标。
pivotY:参考pivotX
加速器如下:
@android:anim/accelerate_interpolator: 越来越快
@android:anim/decelerate_interpolator:越来越慢
@android:anim/accelerate_decelerate_interpolator:先快后慢
@android:anim/anticipate_interpolator: 先后退一小步然后向前加速
@android:anim/overshoot_interpolator:快速到达终点超出一小步然后回到终点
@android:anim/anticipate_overshoot_interpolator:到达终点超出一小步然后回到终点
@android:anim/bounce_interpolator:到达终点产生弹球效果,弹几下回到终点
@android:anim/linear_interpolator:均匀速度。
ObjectAnimator使用示例:
ObjectAnimator rotationXAnimator = ObjectAnimator.ofFloat(target,
"rotationX",
0f, 360f);
rotationXAnimator.setRepeatCount(1);
rotationXAnimator.setDuration(3000);
rotationXAnimator.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator bgColorAnimator = ObjectAnimator.ofArgb(mPuppet,
"backgroundColor",
0xff009688, 0xff795548);
bgColorAnimator.setRepeatCount(1);
bgColorAnimator.setDuration(3000);
bgColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
bgColorAnimator.setStartDelay(0);
其中属性可选,rotationX,rotationY,translationX、translationY、translationZ、scaleX、scaleY、alpha、等,规则就是,在View中查找设置属性的方法set(具体属性),将具体属性中的首字母改成小写即可,如: View.setRotationX, 在ObjectAnimator中对应的的属性名称就是rotationX。
PropertyValuesHolder示例:
也可以直接使用PropertyValuesHolder来设置动画,如下:
PropertyValuesHolder bgColorAnimator = PropertyValuesHolder.ofObject("backgroundColor",
new ArgbEvaluator(),
0xff009688, 0xff795548);
PropertyValuesHolder rotationXAnimator = PropertyValuesHolder.ofFloat("rotationX",
0f, 360f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mPuppet, bgColorAnimator, rotationXAnimator);
objectAnimator.setDuration(3000);
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator中的设置方法,如ofFloat最终使用的就是PropertyValuesHolder,来存储将要修改的属性内容和属性值
ValueAnimator使用示例:
ObjectAnimator继承自ValueAnimator,直接使用ValueAnimator有相比ObjectAnimator更广泛的灵活性,只是使用难度稍大,如下将修改target的宽与高做成动画效果:
final int height = target.getLayoutParams().height;
final int width = target.getLayoutParams().width;
ValueAnimator sizeValueAnimator = ValueAnimator.ofFloat(1f, 3f);
sizeValueAnimator.setDuration(3000);
sizeValueAnimator.setRepeatCount(1);
sizeValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
sizeValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float animatedValue = (float) valueAnimator.getAnimatedValue();
target.getLayoutParams().height = (int) (height * animatedValue);
target.getLayoutParams().width = (int) (width * animatedValue);
target.requestLayout();
}
});
ValueAnimator使用自定义数据计算器,可实现更加多样化的动画进度展现
private Animator getValueAnimatorByCustom() {
final int height = target.getLayoutParams().height;
final int width = target.getLayoutParams().width;
PropertyBean startPropertyBean = new PropertyBean(0xff009688, 0f, 1f);
PropertyBean endPropertyBean = new PropertyBean(0xff795548, 360f, 3.0f);
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setInterpolator(new SpeedUpInterpolator());//custom interpolator
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.setRepeatCount(1);
valueAnimator.setObjectValues(startPropertyBean, endPropertyBean);
valueAnimator.setEvaluator(new MyTypeEvaluator());//custom evaluator
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
PropertyBean propertyBean = (PropertyBean) valueAnimator.getAnimatedValue();
if (propertyBean.getBackgroundColor() != 0 && propertyBean.getBackgroundColor() != 1) {
target.setBackgroundColor(propertyBean.getBackgroundColor());
}
target.setRotationX(propertyBean.getRotationX());
target.getLayoutParams().height = (int) (height * propertyBean.getSize());
target.getLayoutParams().width = (int) (width * propertyBean.getSize());
target.requestLayout();
}
});
return valueAnimator;
}
public class PropertyBean {
int backgroundColor;
float rotationX;
float size;
public PropertyBean(int backgroundColor, float rotationX, float size) {
this.backgroundColor = backgroundColor;
this.rotationX = rotationX;
this.size = size;
}
public int getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
}
public float getRotationX() {
return rotationX;
}
public void setRotationX(float rotationX) {
this.rotationX = rotationX;
}
public float getSize() {
return size;
}
public void setSize(float size) {
this.size = size;
}
}
public class MyTypeEvaluator implements TypeEvaluator<PropertyBean> {
ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();
@Override
public PropertyBean evaluate(float fraction, PropertyBean startPropertyBean, PropertyBean endPropertyBean) {
int currentColor = (int) mArgbEvaluator.evaluate(fraction, startPropertyBean.getBackgroundColor(), endPropertyBean.getBackgroundColor());
float currentRotationX = startPropertyBean.getRotationX() + (endPropertyBean.getRotationX() - startPropertyBean.getRotationX()) * fraction;
float currentSize = startPropertyBean.getSize() + (endPropertyBean.getSize() - startPropertyBean.getSize()) * fraction;
return new PropertyBean((int) currentColor, currentRotationX, currentSize);
}
}
控件状态动画使用示例:
通过animated-selector实现控件在不用状态下展示不用动画或者背景的需求,用例如下:
<!-- provide a different drawable for each state -->
<item
android:id="@+id/pressed"
android:drawable="@drawable/img29"
android:state_pressed="true"/>
<item
android:id="@id/default1"
android:drawable="@drawable/img1"/>
<!-- specify a transition -->
<transition
android:fromId="@+id/default1"
android:toId="@+id/pressed">
<animation-list>
<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"/>
<item
android:drawable="@drawable/img6"
android:duration="100"/>
<item
android:drawable="@drawable/img7"
android:duration="100"/>
<item
android:drawable="@drawable/img8"
android:duration="100"/>
<item
android:drawable="@drawable/img9"
android:duration="100"/>
<item
android:drawable="@drawable/img10"
android:duration="100"/>
<item
android:drawable="@drawable/img13"
android:duration="100"/>
<item
android:drawable="@drawable/img14"
android:duration="100"/>
<item
android:drawable="@drawable/img15"
android:duration="100"/>
<item
android:drawable="@drawable/img17"
android:duration="100"/>
<item
android:drawable="@drawable/img18"
android:duration="100"/>
<item
android:drawable="@drawable/img19"
android:duration="100"/>
<item
android:drawable="@drawable/img20"
android:duration="100"/>
<item
android:drawable="@drawable/img21"
android:duration="100"/>
<item
android:drawable="@drawable/img22"
android:duration="100"/>
<item
android:drawable="@drawable/img23"
android:duration="100"/>
<item
android:drawable="@drawable/img24"
android:duration="100"/>
<item
android:drawable="@drawable/img25"
android:duration="100"/>
<item
android:drawable="@drawable/img26"
android:duration="100"/>
<item
android:drawable="@drawable/img27"
android:duration="100"/>
<item
android:drawable="@drawable/img28"
android:duration="100"/>
<item
android:drawable="@drawable/img29"
android:duration="100"/>
</animation-list>
</transition>