您的位置:首页 > 移动开发 > Android开发

android 里的动画,自己的一些总结

2018-01-14 18:48 567 查看
不要抱怨身边的环境,去改变自己,让自己拥有更好的环境。

前言

移动端开发界面有时候要加入一些动画,android里有2类动画,第一类是View动画(View动画里又分2类,一类是帧动画,另一类是补间动画),另一类是属性动画;顾名思义View动画只能操作View对象,但是并不会改变View的属性。如果想要通过动画改变对象的属性值,这时候我们可以考虑使用属性动画来实现效果了。

补间(Tween)动画

透明度(alpha)、缩放(scale)、平移(translate)、旋转(rotate)


透明度(alpha)

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:repeatCount="3"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000">
</alpha>


android:fromAlpha 动画开始的透明度,从0.0 –1.0 ,0.0表示全透明,1.0表示完全不透明

android:toAlpha 动画结束时的透明度,也是从0.0 –1.0 ,0.0表示全透明,1.0表示完全不透明

缩放(scale)

<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0"
android:fromYScale="0"
android:toXScale="2"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="3"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000" />


android:pivotX 当取50%时:在原点坐标的基础上加上的自己宽度的50%;50:在原点坐标的基础上加上50;50%p:在原点坐标的基础上加上父控件的50%

android:pivotY 缩放起点Y轴坐标,取值及意义跟android:pivotX一样

android:fromXScale 起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;

android:toXScale 结尾的X方向上相对自身的缩放比例,浮点值;

android:fromYScale 起始的Y方向上相对自身的缩放比例,浮点值,

android:toYScale 结尾的Y方向上相对自身的缩放比例,浮点值;

平移(translate)

<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100"
android:fromYDelta="130"
android:toXDelta="50"
android:toYDelta="150"
android:repeatCount="1"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000" />


android:fromXDelta 起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义已在scale标签中讲述,这里就不再重讲

android:fromYDelta 起始点Y轴从标,可以是数值、百分数、百分数p 三种样式;

android:toXDelta 结束点X轴坐标

android:toYDelta 结束点Y轴坐标

旋转(rotate)

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="-360"   负数逆时针 正数顺时针
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000" />


android:pivotX 同上

android:pivotY 同上

我们可以发现,透明度(alpha)、缩放(scale)、平移(translate)、旋转(rotate)这四种动画有一些共同的属性:

Animation类继承的属性(因为这4种动画都是继承Animation)

android:repeatCount="1"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000"
android:interpolator="@animator/animatortest"
....


android:duration 动画持续时间,以毫秒为单位

android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态

android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态

android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态

android:repeatCount 重复次数

android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。

android:interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等

动画集合(Set)

如果我们想让View进行缩放的动画的同时旋转,再平移,同时透明度也跟着改变;set没有私有的属性,set也继承Animation, set里使用的Animation的所有属性都同时作用与set的字节点。

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true">
<translate
android:fromXDelta="0"
android:toXDelta="-300" />
<alpha
android:fromAlpha="0"
android:toAlpha="1.0"/>
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"/>
<rotate
android:fromDegrees="0"
android:toDegrees="720"
android:pivotX="50%"
android:pivotY="50%"/>
</set>


属性值同上面;

但是要注意以set里的属性为主,

怎么在code里使用这些xml定义的动画?

Animation animation = AnimationUtils.loadAnimation(this, R.anim.alphaanim);   // res目录下创建一个anim文件夹
findViewById(R.id.tv_test).startAnimation(animation);  //使用xml 生成动画


如果我们不想使用xml,用代码实现动画。

scale 动画使用代码实现:

ScaleAnimation scaleAnimation = new ScaleAnimation(1, 1, 2, 2);
scaleAnimation.setDuration(1000);
scaleAnimation.setFillEnabled(true);
scaleAnimation.setInterpolator(new BounceInterpolator());   //设置插值器  比如先加速 后减速等

public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
//  构造方法里参数对应着上面的xml实现的动画的属性
mResources = null;
mFromX = fromX;
mToX = toX;
mFromY = fromY;
mToY = toY;
mPivotX = 0;
mPivotY = 0;
}

findViewById(R.id.tv_test).startAnimation(animation);  //开始动画


set联合动画使用代码实现:

AnimationSet setAnim = new AnimationSet(true);
setAnim.addAnimation(rotateAnim);
setAnim.addAnimation(scaleAnimation);  //对应上面的scaleAnimation  其他的rotateAnim等同理
setAnim.addAnimation(translateAnimation);
setAnim.setDuration(3000);
setAnim.setFillAfter(true);
mTvTest.startAnimation(setAnim);


属性(Property Animator)动画

1.Property Animation是API Level 11(Android 3.0)引入的;

2.Property Animator包括ValueAnimator和ObjectAnimator。

属性动画ValueAnimator

public void testValueAnimator() {
ValueAnimator animator = ValueAnimator.ofInt(0, 400);
ValueAnimator.AnimatorUpdateListener animatorUpdateListener;
animator.addUpdateListener(animatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
}
});
animator.setDuration(2000);
animator.start();
}


通过注册一个监听方法,int value = (int) animation.getAnimatedValue();得到当前进度的具体值(0-400);还有ofFloat(), ofObject(), ofArgb()等;ofObject()要指定一个TypeEvaluator(这个是将当前进度转为具体值的类); 因为ofInt() ofFloat等系统都有相应的TypeEvaluator,所以不需要我们再指定。

属性动画ObjectAnimator

该动画继承ValueAnimator;
public final class ObjectAnimator extends ValueAnimator


public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
// target: 即将动画的对象;propertyName: 对象要改变的属性;

public void testObjectAnimatorByTranslationX() {
//translationX translationY translation  平移
//alphaX alphaY  透明度
//rotation rotationX rotationY 旋转
//scaleX scaleY 缩放
ObjectAnimator animator = ObjectAnimator.ofFloat(mTvTest, "translationZ", 100, 0, 200);
animator.setDuration(2000);
animator.start();
}
// mTvTest: TextView对象 在TextView里没有发现setTranslationZ(),最后在他的父类View里面发现了。
public void setTranslationZ(float translationZ) {
if (translationZ != getTranslationZ()) {
invalidateViewProperty(true, false);
mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
// 动画通过改变translationZ属性值,通过反射得到setTranslationZ方法(String methodName = getMethodName("set", mPropertyName);),进而调用该方法。invalidateViewProperty 重绘View;
invalidateParentIfNeededAndWasQuickRejected();
}
}


我们动画的对象属性没有相应的setter方法,我们可以重写该类,提供对应的属性的setter;

比如我们想对象的pointRadio属性动画:

public class MyView extends View {
private Point mPoint = new Point(100);
public MyView(Context context) {
super(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(100, 100, mPoint.getmRadio(), paint);
}
public void setPointRadio(int radio) {
mPoint.setmRadio(radio);
invalidate();  // 从上面的解释 动画是通过反射调用属性的setter,我们在这里改变属性的值,然后再重绘!
}
//如果只给动画设置一个值时,会调用该方法得到 初始值  没有定义该方法  会用默认值 int :0
public int getPointRadio() {
return 50;
}
}


其他api

ofObject等都大同小异;ofObject() 我们通过ValueAnimator知道,要指定一个TypeEvaluator;

TypeEvaluator(评估者)

将动画的进度转为对应的值 这里只贴一个自定义的TypeEvaluator


public class CharEvaluator implements TypeEvaluator<Character> {
@Override
public Character evaluate(float fraction, Character startValue, Character endValue) {
// fraction: 进度值
int startInt = startValue;
int endInt = endValue;
int type =  (int) (startInt + fraction * (endInt - startInt));
return (char)type;
}
}


Interpolator(插值器)

控制动画的进度


@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

public LinearInterpolator() {
}

public LinearInterpolator(Context context, AttributeSet attrs) {
}

public float getInterpolation(float input) {
return input;    // input: 表示当前的进度 我们自定义插值器的时候一般实现TimeInterpolator类
/**
abstract public class BaseInterpolator implements Interpolator
public interface Interpolator extends TimeInterpolator
public interface TimeInterpolator {
float getInterpolation(float input);
}
*/
}

/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}


Keyframe(关键帧)

用来指定进度对应的相应属性值,比如我要在动画进行到0.3的时候对应的数值是多少。这样可以取代一些插值器的自定义,他们都是用来控制动画的进度!


public static Keyframe ofObject(float fraction, Object value)
// fraction: 进度值 value: 当前进度对应的属性值
private void PropertyValuesHolderByOfObject() {
Keyframe keyframe1 = Keyframe.ofObject(0f, new Character('A'));   // 0f: 动画刚开始的时候
Keyframe keyframe2 = Keyframe.ofObject(0.1f, new Character('L'));
Keyframe keyframe3 = Keyframe.ofObject(1f, new Character('Z')); // 1f: 动画结束的时候
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("char", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mPropertyView, holder);
animator.setEvaluator(new CharEvaluator());
animator.setDuration(3000);
animator.start();
}


PropertyValuesHolder

保存动画的属性等信息


public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)
// propertyName: 对象的属性  values:指定当前对象的属性具体的进度对应的数值

PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("char", keyframe1, keyframe2, keyframe3); // 上面介绍了,反射对象的setChar方法 来改变对象的属性;


PropertyValuesHolder怎么被使用?

ValueAnimator,ObjectAnimator都有相应的ofPropertyValuesHolder方法。


public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)
// target: 要使用动画的对象 values: 可以指定多个属性 进而可以使动画对象的多个属性同时变化,比如我们在平移的时候背景颜色也一同变化。一些情况下可以取代下面介绍的AnimatorSet(联合动画)。


AnimatorSet(联合动画)

/**
* playSequentially:依次执行动画
* playTogether:一起执行动画
*/
public void AnimatorSetByPlaySequentially() {
ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTvTest, "translationX", 100, 0, 200);
ObjectAnimator bgAnimator = ObjectAnimator.ofInt(mPropertyView, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(translationAnimator, bgAnimator);
animatorSet.setDuration(2000);
animatorSet.start();
}

public void AnimatorSetByPlay() {
//with 一起执行   before 后执行  after 先执行
ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTvTest, "translationX", 100, 0, 200);
ObjectAnimator bgAnimator = ObjectAnimator.ofInt(mPropertyView, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet.Builder builder = animatorSet.play(translationAnimator);
builder.after(bgAnimator); // after 先执行
animatorSet.setDuration(2000);
animatorSet.start();
}


总结

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息