这里会讲到的动画有视图动画(帧动画,补间动画),属性动画,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>
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>
<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>
/** *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()方法.
使用步骤:
应用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); } }
<?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>
<?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>
<?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>