android中的动画完全总结

这里会讲到的动画有视图动画(帧动画,补间动画),属性动画,activity和fragment切换时的动画,viewgroup添加和移除子view时的动画,android随后新的系统api的transition,Scene实现过渡效果,内容还是很多的。下面一一来说。

在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animator(属性动画);其中 
View Animation包括Tween Animation(补间动画)和Frame Animation(逐帧动画); 
Property Animator包括ValueAnimator和ObjectAnimation;

1.帧动画:

<span style="font-size:14px;">	/**
	 * 帧动画就是搞几个图片让他轮播
	 * 在res/drawable下定义xml文件
	 * <?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" 
    android:oneshot="true">
    <item
        android:drawable="@drawable/iv1"
        android:duration="150">
    </item>
    <item
        android:drawable="@drawable/iv2"
        android:duration="150">
    </item>
    <item
        android:drawable="@drawable/iv3"
        android:duration="150">
    </item>
</animation-list>
将xml作为imageview的背景图片
代码中调用 imageview.getbackground强转为AnimationDrawable
调用start..
调用stop
	 */</span>


2.补间动画:有xml定义或者java文件定义都可以

xml中定义:

<span style="font-size:14px;">	 * Android的animation由四种类型组成:alpha、scale、translate、rotate
	 * 还有个动画集合set可以把以上动画放在一起同时执行
	 * 可以用xml文件定义res/anim文件夹下
	 * 
	 * 1.scale标签是缩放动画,可以实现动态调控件尺寸的效果,有下面几个属性:
android:fromXScale    起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;
android:toXScale        结尾的X方向上相对自身的缩放比例,浮点值;
android:fromYScale    起始的Y方向上相对自身的缩放比例,浮点值,
android:toYScale        结尾的Y方向上相对自身的缩放比例,浮点值;
android:pivotX            缩放起点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,当为数值时,表示在当前View的左上角,即原点处加上50px,做为起始缩放点;如果是50%,表示在当前控件的左上角加上自己宽度的50%做为起始点;如果是50%p,那么就是表示在当前的左上角加上父控件宽度的50%做为起始点x轴坐标。(具体意义,后面会举例演示)
android:pivotY           缩放起点Y轴坐标,取值及意义跟android:pivotX一样。
	 * 
	 * 
	 * android:fillAfter   如果设置为true,控件动画结束时,将保持动画最后时的状态
	 * android:fillBefore       如果设置为true,控件动画结束时,还原到开始动画前的状态
	 *android:repeatCount 重复次数
android:repeatMode	重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。
android:interpolator  设定插值器,其实就是指定的动作效果,比如弹跳效果等,不在这小节中讲解,后面会单独列出一单讲解。
	 * 
	 * 
	 * 2.
	 * alpha标签——调节透明度
1、自身属性
android:fromAlpha   动画开始的透明度,从0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
android:toAlpha       动画结束时的透明度,也是从0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
	 
	 
	 3.Rotate
	 android:fromDegrees     开始旋转的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
android:toDegrees         结束时旋转到的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
android:pivotX               缩放起点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义已在scale标签中讲述,这里就不再重讲
android:pivotY               缩放起点Y轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p
	
	
	4.translate标签所具有的属性为:
android:fromXDelta     起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义已在scale标签中讲述,这里就不再重讲
android:fromYDelta    起始点Y轴从标,可以是数值、百分数、百分数p 三种样式;
android:toXDelta         结束点X轴坐标
android:toYDelta        结束点Y轴坐标
	 *
	 */</span>

除了上面4个外,还有一个AnimationSet,是可以将上面动画组合在一起的。

xml中定义后,使用下面的代码应用动画,

<span style="font-size:14px;">	public static void start(View view){
//		AnimationSet set = new AnimationSet(true);
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.scale_anim));
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.alpha_anim));
//		set.addAnimation(AnimationUtils.loadAnimation(this, R.anim.rotate_anim));
//
//		set.setAnimationListener(new AnimationListener() {
//			@Override
//			public void onAnimationStart(Animation animation) {
//			}
//
//			@Override
//			public void onAnimationRepeat(Animation animation) {
//			}
//
//			@Override
//			public void onAnimationEnd(Animation animation) {
//				view.startAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.translate_anim));
//			}
//		});
//		view.startAnimation(set);
		
		view.startAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.set_anim));
	}</span>
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <alpha
        android:duration="2500"
        android:fromAlpha="0"
        android:toAlpha="1" />
</set></span>

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set>

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

</set></span>

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    
  <scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:fromXScale="0"
    android:toXScale="1"  
    android:fromYScale="0"  
    android:toYScale="1"  
    android:pivotX="67%p"  
    android:pivotY="67%p"  
    android:duration="2500" />

</set></span>

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set></span>

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

    <alpha
        android:duration="2500"
        android:fromAlpha="0"
        android:toAlpha="1" />

    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="67%p"
        android:pivotY="67%p"
        android:toXScale="1"
        android:toYScale="1" />

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="2500"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set></span>

<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000" >

    <translate
        android:fromXDelta="-50%p"
        android:toXDelta="0" />

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

</set></span>



java代码创建补间动画,

只是根据xml中定义的,翻译成java代码就可以了。

如xml中定义了,

<span style="font-size:14px;">	/**
	 * 代码生成animation。xml文件对应的Java类
	 * 	TranslateAnimation
		RotateAnimation
		ScaleAnimation
		AlphaAnimation
		我们可以根据xml中的属性翻译过来就行了
	 */
	
	//例如这个:
	/**
	 * <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <rotate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" >
    </rotate>

    <alpha
        android:duration="2500"
        android:fromAlpha="0"
        android:toAlpha="1" />

    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="67%p"
        android:pivotY="67%p"
        android:toXScale="1"
        android:toYScale="1" />

    <translate
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="2500"
        android:toXDelta="67%p"
        android:toYDelta="67%p" >
    </translate>

</set>
	 */</span>

那么如果我们用java代码来生成的话就是这样的:

<span style="font-size:14px;">	public static void start(View view){
		RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		rotateAnimation.setFillAfter(true);
		rotateAnimation.setDuration(2500);
		
		AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
		alphaAnimation.setDuration(2500);
		
		ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_PARENT,0.67f, Animation.RELATIVE_TO_PARENT, 0.67f);
		scaleAnimation.setDuration(2500);
		
		TranslateAnimation translateAnimation = new TranslateAnimation( Animation.RELATIVE_TO_PARENT, 0,  Animation.RELATIVE_TO_PARENT, 0.67f,  Animation.RELATIVE_TO_PARENT, 0,  Animation.RELATIVE_TO_PARENT, 0.67f);
		translateAnimation.setStartOffset(2500);
		translateAnimation.setDuration(2500);
		
		AnimationSet set = new AnimationSet(true);
		set.addAnimation(rotateAnimation);
		set.addAnimation(alphaAnimation);
		set.addAnimation(scaleAnimation);
		set.addAnimation(translateAnimation);
		view.startAnimation(set);
	}</span>

上面的代码还是很简单的,想想如果位置从A平移到B,是应该以什么样的速率来移动呢,默认的是匀速了,所有你也可以指定或者自定义动画过程中要用到的插值器,Interpolator插值器,用来定义动画执行过程中的具体行为,变化速率。插值器也可以用在属性动画上。

	/**
	 *Interpolator插值器,用来定义动画执行过程中的具体行为,变化速率 
	 *
	 *已经定义好了的插值器有这些
	 *AccelerateDecelerateInterpolator   在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator                     在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator                      开始的时候向后然后向前甩
AnticipateOvershootInterpolator     开始的时候向后然后向前甩一定值后返回最后的值
BounceInterpolator                          动画结束的时候弹起
CycleInterpolator                             动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator                    在动画开始的地方快然后慢
LinearInterpolator                            以常量速率改变
OvershootInterpolator                      向前甩一定值后再回到原来位置
	 */
应用插值器,
	public static void useSystemInterpolator(View view,Interpolator i){
		AnimationSet set = new AnimationSet(true);
		set.addAnimation(AnimationUtils.loadAnimation(view.getContext(), R.anim.scale_anim));
		set.setInterpolator(i);
		view.startAnimation(set);
	}


3.属性动画,也可以用xml或者java定义。

涉及到2个类

ValueAnimator,这个本身不能对view造成动画效果,它是根据指定属性的起始值,可选指定插值器,添加监听动画回调变化过程中的返回值,根据返回值来动态改变view的属性值。
ObjectAnimator,对象动画,直接作用于view
/**
 * 补间动画虽能对控件做动画,但并没有改变控件内部的属性值。 比如平移后,虽然外观上位置看像移动了,其实是没有移动
 * 
 * 属性动画,ValueAnimator; 它本身不会对任何view做操作,需要我们监听它的值变化,
 * 在变化中自己改变view的值,从而实现动画.至于这个区间的值变化是怎样的,我们可以自己去
 * 设置它的animator.setInterpolator(new BounceInterpolator());
 * 
 * 而和它的子类ObjectAnimator关联了我们要动画的对象,这样子我们就不需要
 * 每次监听变化了
 */

xml定义,
    /**
     * xml文件中定义属性动画
     * 标签对应;
     * <value_animator />:对应ValueAnimator
     <objectAnimator />:对应ObjectAnimator
     <set />:对应AnimatorSet
     *
     * <value_animator
     android:duration="int"
     android:valueFrom="float | int | color"
     android:valueTo="float | int | color"
     android:startOffset="int"
     android:repeatCount="int"
     android:repeatMode=["repeat" | "reverse"]
     android:valueType=["intType" | "floatType"]
     android:interpolator=["@android:interpolator/XXX"]/>
     */
    public static void loadXmlAnimator(final View view){
//        ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.value_animator);
//        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                int offset = (int)animation.getAnimatedValue();
//                view.layout( offset,offset,view.getWidth()+offset,view.getHeight() + offset);
//            }
//        });
//        valueAnimator.start();

//        ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(view.getContext(), R.animator.object_animator);
//        objectAnimator.setTarget(view);
//        objectAnimator.start();

        AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(view.getContext(), R.animator.set_animator);
        set.setTarget(view);
        set.start();
    }

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="TranslationY"
    android:duration="2000"
    android:valueFrom="0.0"
    android:valueTo="400.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:valueType="floatType"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:startOffset="2000"/>

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="rotation"
    android:repeatCount="1"
    android:valueFrom="0"
    android:valueTo="360"
    android:valueType="floatType" >

</objectAnimator>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <objectAnimator
        android:propertyName="x"
        android:duration="2500"
        android:valueFrom="0"
        android:valueTo="400"
        android:valueType="floatType"/>
    <objectAnimator
        android:propertyName="y"
        android:duration="2500"
        android:valueFrom="0"
        android:valueTo="300"
        android:valueType="floatType"/>
</set>

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:anim/bounce_interpolator"
    android:startOffset="2000"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="intType" />




java中定义,

package com.example.customeviewserial.property_animation;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.example.customeviewserial.R;

/**
 * GroupFlexBoll提供一个例子说明用java代码创建属性动画
 *关键代码startTranslate()方法
 *  */
public class GroupFlexBoll extends RelativeLayout {
	private static final int[] BTN_RES = { R.drawable.home,
			R.drawable.iv1, R.drawable.iv2,
			R.drawable.iv3 };
	private static final int SWAP_ANGLE = 90;
	private static final int BOLLNUM = 3;
	private static final float SPACE_ANGLE = SWAP_ANGLE / (BOLLNUM - 1);
	RelativeLayout.LayoutParams params;
	private int radius;
	private ImageView homeImageView;
	private ImageView iv1;
	private ImageView iv2;
	private ImageView iv3;

	public GroupFlexBoll(Context context, AttributeSet attrs) {
		super(context, attrs);
		addView(context);
	}

	private void addView(Context context) {
		homeImageView = new ImageView(context);
		homeImageView.setTag("home");
		params = new RelativeLayout.LayoutParams(40, 40);
		params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		homeImageView.setImageResource(BTN_RES[0]);
		addView(homeImageView, params);

		iv1 = new ImageView(context);
		iv1.setImageResource(BTN_RES[1]);
		iv1.setTag("iv1");
		addView(iv1, params);

		iv2 = new ImageView(context);
		iv2.setImageResource(BTN_RES[2]);
		iv2.setTag("iv2");
		addView(iv2, params);

		iv3 = new ImageView(context);
		iv3.setImageResource(BTN_RES[3]);
		iv3.setTag("iv3");
		addView(iv3, params);

		setSubBtnVisible(false);
	}

	public void setOperationListener(OnClickListener l) {
		homeImageView.setOnClickListener(l);
		iv1.setOnClickListener(l);
		iv2.setOnClickListener(l);
		iv3.setOnClickListener(l);
	}

	private void setSubBtnVisible(boolean isVisible) {
		if (isVisible) {
			iv1.setVisibility(View.VISIBLE);
			iv2.setVisibility(View.VISIBLE);
			iv3.setVisibility(View.VISIBLE);
		} else {
			iv1.setVisibility(View.GONE);
			iv2.setVisibility(View.GONE);
			iv3.setVisibility(View.GONE);
		}
	}
	
	private void setSubBtnEnable(boolean isEnabled){
		if(isEnabled){
			iv1.setEnabled(true);
			iv2.setEnabled(true);
			iv3.setEnabled(true);
		}else{
			iv1.setEnabled(false);
			iv2.setEnabled(false);
			iv3.setEnabled(false);
		}
	}

	private boolean isOpend = false;
	private int boll_radius;

	public void toggle() {
		isOpend = !isOpend;
		doAnimation();
	}

	private void doAnimation() {
		setSubBtnVisible(true);
		startTranslate();
	}

	private void startTranslate() {
		int willTranslateLen = boll_radius * 2 * 3;
		ObjectAnimator animator1Y, animator2Y, animator3Y, animator1X, animator2X, animator3X;
		if (isOpend) {
			animator1Y = ObjectAnimator.ofFloat(iv1, "translationY", 0,
					-willTranslateLen);
			animator2Y = ObjectAnimator.ofFloat(iv2, "translationY", 0,
					(float) (-willTranslateLen * Math.cos(Math.toRadians(45))));
			animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);

			animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
			animator2X = ObjectAnimator.ofFloat(iv2, "translationX", 0,
					(float) (-willTranslateLen * Math.sin(Math.toRadians(45))));
			animator3X = ObjectAnimator.ofFloat(iv3, "translationX", 0,
					(float) (-willTranslateLen * Math.sin(Math.toRadians(90))));
		} else {
			animator1Y = ObjectAnimator.ofFloat(iv1, "translationY",
					-willTranslateLen, 0);
			animator2Y = ObjectAnimator.ofFloat(iv2, "translationY",
					(float) (-willTranslateLen * Math.cos(Math.toRadians(45))),
					0);
			animator3Y = ObjectAnimator.ofFloat(iv3, "translationY", 0, 0);

			animator1X = ObjectAnimator.ofFloat(iv1, "translationX", 0, 0);
			animator2X = ObjectAnimator.ofFloat(iv2, "translationX",
					(float) (-willTranslateLen * Math.sin(Math.toRadians(45))),
					0);
			animator3X = ObjectAnimator.ofFloat(iv3, "translationX",
					(float) (-willTranslateLen * Math.sin(Math.toRadians(90))),
					0);
		}

		Animator rotateAnimator1 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		Animator rotateAnimator2 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		Animator rotateAnimator3 = AnimatorInflater.loadAnimator(getContext(), R.animator.rotate);
		rotateAnimator1.setTarget(iv1);
		rotateAnimator2.setTarget(iv2);
		rotateAnimator3.setTarget(iv3);
		rotateAnimator1.setDuration(100);
		rotateAnimator2.setDuration(100);
		rotateAnimator3.setDuration(100);
		
		AnimatorSet set = new AnimatorSet();
		set.addListener(new AnimatorListener() {
			@Override
			public void onAnimationStart(Animator animation) {
				homeImageView.setEnabled(false);
				setSubBtnEnable(false);
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				if (isOpend == false) {
					setSubBtnVisible(false);
				}else{
					setSubBtnEnable(true);
				}
				homeImageView.setEnabled(true);
			}

			@Override
			public void onAnimationCancel(Animator animation) {
			}
		});
		set.playTogether(animator1Y, animator2Y, animator3Y, animator1X,
				animator2X, animator3X,rotateAnimator1,rotateAnimator2,rotateAnimator3);
		set.setDuration(1500);
		if(isOpend){
			set.setInterpolator(new BounceInterpolator());
		}else{
			set.setInterpolator(new AccelerateInterpolator());
		}
		set.start();
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			int measuredWidth = getMeasuredWidth();
			int measuredHeight = getMeasuredHeight();
			radius = Math.min(measuredWidth, measuredHeight);

			measureBtnSize();
		}
	}

	private void measureBtnSize() {
		params.width = radius / 4;
		params.height = radius / 4;

		boll_radius = radius / 8;

		homeImageView.setLayoutParams(params);
		iv1.setLayoutParams(params);
		iv2.setLayoutParams(params);
		iv3.setLayoutParams(params);
	}

}

控制动画顺序,
package com.example.customeviewserial.set_order_animator;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;

/**
 * Created by Administrator on 2016/5/24 0024.
 */
public class GuideUser {
    /**
     * AnimatorSet实现的属性动画集合,
     * 控制各个动画的执行顺序
     * playSequentially,playTogether
     */
    public static void startAnimatorSet(View... view){
        ObjectAnimator tv1BgAnimator = ObjectAnimator.ofInt(view[0], "BackgroundColor",  0xffff00ff, 0xffffff00, 0xffff00ff);
        ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(view[1], "translationY", 0, 300, 0);
        ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(view[2], "translationY", 0, 400, 0);
        AnimatorSet animatorSet = new AnimatorSet();
//      animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
        animatorSet.playTogether(tv1BgAnimator,tv1TranslateY,tv2TranslateY);

        //自由设置动画顺序——AnimatorSet.Builder
        AnimatorSet.Builder builder = animatorSet.play(tv1BgAnimator);
        /**
         * //和前面动画一起执行
         public Builder with(Animator anim)
         //执行先执行这个动画再执行前面动画
         public Builder before(Animator anim)
         //执行前面的动画后才执行该动画
         public Builder after(Animator anim)
         //延迟n毫秒之后执行动画
         public Builder after(long delay)
         */

//AnimatorSet没有统一设置的情况下,各自按各自的来。这里统一设置了时间,会覆盖各自的时间
        animatorSet.setDuration(1000);

        animatorSet.start();
    }
}

4.viewgroup初始化,viewgroup中添加和移除子view时添加动画;
涉及到LayoutTransition和之前提到的属性动画;
 
	/**
	 * 普通viewGroup添加进入统一动画的LayoutAnimation
	 * 和针对grideView添加进入动画的gridLayoutAnimation; 这2个类只能保证在创建的时候有动画。
	 * 
	 * android:animateLayoutChanges==true可以为任何viewgroup控件加上默认动画
	 * 和LayoutTransition则可以来自定义动画
	 * 
	 * 1.可以在xml文件中指定
	 * 在anim文件夹中定义<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/slide_in_left"
    android:animationOrder="normal"
    android:delay="1" />
    delay值是animation时间值的倍数
    animation引用的只能是animation动画,不能是animator
    
    定义好后,在layout中引用  android:layoutAnimation="@anim/layout_animation"
    动画只在第一次创建容器的时候有动画
    android:animationOrder指viewGroup中的控件动画开始顺序,取值有normal(正序)、reverse(倒序)、random(随机)
    
    
    2.可以在Java文件中指定
    //代码设置通过加载XML动画设置文件来创建一个Animation对象;
        Animation animation= AnimationUtils.loadAnimation(this,R.anim.slide_in_left);   //得到一个LayoutAnimationController对象;
        LayoutAnimationController controller = new LayoutAnimationController(animation);   //设置控件显示的顺序;
        controller.setOrder(LayoutAnimationController.ORDER_REVERSE);   //设置控件显示间隔时间;
        controller.setDelay(0.3f);   //为ListView设置LayoutAnimationController属性;
        mListView.setLayoutAnimation(controller);
        mListView.startLayoutAnimation();
        
        
        对应的GridView:
        Animation animation = AnimationUtils.loadAnimation(MyActivity.this,R.anim.slide_in_left);
        GridLayoutAnimationController controller = new GridLayoutAnimationController(animation);
        controller.setColumnDelay(0.75f);
        controller.setRowDelay(0.5f);
        controller.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP|GridLayoutAnimationController.DIRECTION_LEFT_TO_RIGHT);
        controller.setDirectionPriority(GridLayoutAnimationController.PRIORITY_NONE);
        grid.setLayoutAnimation(controller);
        grid.startLayoutAnimation();
        
        
        
        3.LayoutTransition则可以来为viewgroup自定义添加属性动画
        LayoutTransaction transitioner = new LayoutTransition();  
        ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);  
		transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
		linearLayout.setLayoutTransition(mTransitioner); 
		
		第一个参数int transitionType:表示当前应用动画的对象范围,取值有:
APPEARING —— 元素在容器中出现时所定义的动画。
DISAPPEARING —— 元素在容器中消失时所定义的动画。
CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它需要变化的元素所应用的动画
CHANGE_DISAPPEARING —— 当容器中某个元素消失,其它需要变化的元素所应用的动画
	 */


 
/**
	 * 测试LayoutTransition效果
	 * 这里有几点注意事项: 
1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须使用PropertyValuesHolder所构造的动画才会有效果,不然无效!也就是说使用ObjectAnimator构造的动画,在这里是不会有效果的! 
2、在构造PropertyValuesHolder动画时,”left”、”top”属性的变动是必写的。如果不需要变动,则直接写为:
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
3、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果;
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
比如,这里ofInt(“left”,0,100,0)第一个值和最后一个值都是0,所以这里会有效果的,如果我们改为ofInt(“left”,0,100);那么由于首尾值不一致,则将被视为无效参数,将不会有效果! 
4、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中,如果所有参数值都相同,也将不会有动画效果。 
比如
	 */

下面是一个具体例子,
	/**
	 *为viewgroup应用LayoutTransition动画
	 */
	private void useLayoutTransition() {
		LayoutTransition layoutTransition = new LayoutTransition();
		boolean checked = radio_appear.isChecked();
		boolean checked2 = radio_disappear.isChecked();
		boolean checked3 = radio_change_appear.isChecked();
		boolean checked4 = radio_change_disappear.isChecked();
		if (checked || checked2 || checked3 || checked4) {
		} else {
			return;
		}

		if (checked) { // 自身动画添加
			ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null,
					"alpha", 0, 1);
			layoutTransition.setAnimator(LayoutTransition.APPEARING,
					appearAnimator);
		}

		if (checked2) { // 自身移除动画
			ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null,
					"alpha", 1, 0);
			layoutTransition.setAnimator(LayoutTransition.DISAPPEARING,
					disappearAnimator);
		}

		if (checked3) { // 自身添加时对其他控件应用的动画
			PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
					0, 100, 0);
			PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
					0);
			Animator changeAppearAnimator = ObjectAnimator
					.ofPropertyValuesHolder(layout, pvhLeft, pvhTop);
			layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING,
					changeAppearAnimator);
		}

		if (checked4) { // 自身移除时对其他控件应用的动画
			PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",
					0, 0);
			PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0,
					0);
			PropertyValuesHolder pvhRotateX = PropertyValuesHolder.ofFloat(
					"rotationX", 0,180, 0);
			Animator changeDisAppearAnimator = ObjectAnimator
					.ofPropertyValuesHolder(layout, pvhLeft, pvhTop,
							pvhRotateX);
			layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
					changeDisAppearAnimator);
		}
		layoutTransition.setDuration(1000);
//		layoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 500);
		layoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 100);
		layoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 100);//其他条目动画时的间隔
		layout.setLayoutTransition(layoutTransition);
	}


5.在activity和fragment进入和退出时运用动画。这些动画都是对activity或者fragment整体的所有布局元素统一进行相同的动画。
activity的进入和退出的动画,我们可以使用代码中应用:
在startActivity或者finish之后调用overridePendingTransition(int enterAnim,int exitAnim);
这里的动画id是xml中定义的视图动画,enterAnim是进入的那个activity的动画,exitAnim是退出的那个activity的动画。
还有一种方法是使用主题的方式为application或者activity指定主题,例如,
定义主题:
	
<style name="FeelyouWindowAnimTheme" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/in_from_left</item>
        <item name="android:activityOpenExitAnimation">@anim/out_from_right</item>
        <item name="android:activityCloseEnterAnimation">@anim/in_from_right</item>
        <item name="android:activityCloseExitAnimation">@anim/out_from_left</item>
    </style>
    <style name="AnimActivityTheme">
        <item name="android:windowAnimationStyle">@style/FeelyouWindowAnimTheme</item>
    </style>

res/anim/下定义一些视图动画:
in_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="100%p"
        android:toXDelta="0" />
</set>

in_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />
</set>

out_from_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:toXDelta="100%p" />
</set>
out_from_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />
</set>
 
 
应用主题:
  <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AnimActivityTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Main2Activity"></activity>
    </application>

fragment的进入和退出动画如下:

请使用v4包下的Fragment保证兼容,在fragmentTransition提交之前应用动画就行;

  if (null == mFragmentManager) {
                    mFragmentManager = getSupportFragmentManager();
                }

                fragment = new BlankFragment();
                FragmentTransaction fragmentTransaction = mFragmentManager
                        .beginTransaction();
                fragmentTransaction.setCustomAnimations(
                        R.anim.in_from_left,
                        R.anim.out_from_right,
                        R.anim.in_from_right,
                        R.anim.out_from_left);

                fragmentTransaction.add(R.id.container, fragment);

                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();


6.android5.0为我们提供了一种针对activity或者fragment切换过渡时的新动画,不像上面的过渡动画是针对整个的布局元素执行的是同一个动画,android5.0的过渡动画更加丰富,可以针对其中的共享某些元素执行动画。可以根据原理自己写效果了。

提供了三种Transition类型:

进入:一个进入的过渡(动画)决定activity中的所有的视图怎么进入屏幕。
退出:一个退出的过渡(动画)决定一个activity中的所有视图怎么退出屏幕。

共享元素:一个共享元素过渡(动画)决定两个activities之间的过渡,怎么共享(它们)的视图。

</pre><p><pre name="code" class="java"> Transition过渡可以在xml文件中定义或者Java代码创建对应的类,例如在res/transition文件夹下定义它的节点可以是Transition的子类,
 	ChangeBounds
 	ChangeClipBounds
 	ChangeImageTransform
 	ChangeTransform
 	TransitionSet
 	Explode
 	Fade
 	Slide
 TransitionInflater提供将xml中定义的transition转为transition对象
 TransitionManager管理Scene和Transition
 TransitionDrawable实现drawable有过渡效果


 

changeBounds -  改变目标视图的布局边界

changeClipBounds - 裁剪目标视图边界

changeTransform - 改变目标视图的缩放比例和旋转角度

changeImageTransform - 改变目标图片的大小和缩放比例

过渡动画的执行时机;并且传入一个你想要执行的动画

Window.setEnterTransition():设置进入动画

Window.setExitTransition():设置退出效果

Window.setSharedElementEnterTransition():设置共享元素的进入动画

Window.setSharedElementExitTransition():设置共享元素的退出动画

具体使用:

/ /允许使用transitions  

getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);  

//设置一个transition

getWindow().setExitTransition(new Explode());//new Slide()  new Fade() ;

//跳转

startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

为共享元素执行过渡动画时,有点不同:

使用android:transitionName属性给两个布局中的共享元素指定一个相同的名字(名字一定不要写错)

然后执行:startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,view,"shareName").toBundle()); 

如果有多个共享元素使用:

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,  

        Pair.create(view1, "agreedName1"),  

        Pair.create(view2, "agreedName2")); 

退出要使用:在代码中触发通过finishAfterTransition()方法触发返回动画,而不是调用finish()方法.

7.Scene的使用:
api19开始才有的特性,Scene场景,常见使用方法,   public Scene(ViewGroup sceneRoot, View layout)   public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)  Transition过渡,内部包含场景转换时的动画。可能对SurfaceView,TextureView不起作用。 工作原理是,捕捉两个Scene的状态,根据这2个状态的区别创建属性动画Animator.实际上是对属性动画的一个应用,使用更简单的api实现 了复杂的功能。 这些优点将使得我们只用少量代码就可以创建复杂的Activity和Fragment切换动画

使用步骤:

应用scene transition 场景转换 1.创建transition 从xml中Transition mFadeTransition =        TransitionInflater.from(this).        inflateTransition(R.transition.fade_transition);从java中创建,Transition mFadeTransition = new Fade();2.使用TransitionManager.go(mEndingScene, mFadeTransition);

res/transition/fade_transition.xml

<?xml version="1.0" encoding="utf-8"?><fade xmlns:android="http://schemas.android.com/apk/res/android" />

例子:

package com.example.androidtest;

import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.AutoTransition;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;

@TargetApi(Build.VERSION_CODES.KITKAT)
public class MainActivity extends Activity {

	private AutoTransition transition;
	private Scene scene1;
	private Scene scene2;
	private boolean start;
	private ImageView iv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.start_layout);
		iv = (ImageView)findViewById(R.id.iv);
		
		// get the root layout ID
		RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.base);
		
		//场景的定义,首先根布局要一样且定义id;每个场景中具有相同id的视为同一个view实现过渡效果,不同的id则只是简单的渐隐渐显
		scene1 = Scene.getSceneForLayout(rootLayout, R.layout.start_layout,this);
		scene2 = Scene.getSceneForLayout(rootLayout, R.layout.end_layout, this);
		
		// create transition, set properties
		//代码创建过渡,也可以使用xml中定义过渡,再使用TransitionInflater.from(this).inflateTransition(resource)解析
		transition = new AutoTransition();
		transition.setDuration(2000);
		transition.setInterpolator(new AccelerateDecelerateInterpolator());
		// initialize flag
		start = true;
	}
	
	/**
	 * 下面几个效果需要api21
	 * ChangeBounds
 	ChangeClipBounds
 	ChangeImageTransform
 	ChangeTransform
 	TransitionSet
 	
 	Explode
 	Fade
 	Slide
	 * @param v
	 */

	public void changeScene(View v) {
		// check flag
		if (start) {
			TransitionManager.go(scene2, transition);
			start = false;
		} else {
			TransitionManager.go(scene1, transition);
			start = true;
		}
		
		//TransitionDrawable是针对图片之间的过渡
		TransitionDrawable drawable = (TransitionDrawable) iv.getBackground();
		drawable.startTransition(2000);
	}

}


start_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/base"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff000000"
    tools:context=".TransitionsActivity" >

    <ImageView
        android:id="@+id/iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:background="@drawable/transitiondrawable" />

    <ImageButton
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape1" />

    <ImageButton
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape2" />

    <ImageButton
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape3" />

    <ImageButton
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="#00000000"
        android:contentDescription="shape"
        android:onClick="changeScene"
        android:src="@drawable/shape4" />

</RelativeLayout>

end_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#ff000000" 
    android:id="@+id/base" 
    tools:context=".TransitionsActivity"> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn1" 
        android:src="@drawable/shape1" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentRight="true" 
        android:layout_alignParentBottom="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn2" 
        android:src="@drawable/shape2" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentLeft="true" 
        android:layout_alignParentBottom="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn3" 
        android:src="@drawable/shape3" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentRight="true" 
        android:layout_alignParentTop="true" 
        android:onClick="changeScene"/> 

    <ImageButton 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/btn4" 
        android:src="@drawable/shape4" 
        android:background="#00000000" 
        android:contentDescription="shape" 
        android:layout_alignParentLeft="true" 
        android:layout_alignParentTop="true" 
        android:onClick="changeScene"/> 

</RelativeLayout>

res/drawable/transitiondrawable.xml

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@drawable/shape1">
    </item>
    <item android:drawable="@drawable/shape2">
    </item>

</transition>



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值