View动画
View动画的对象是View,View动画只改变View的显示,并不影响View的响应区域。它支持四种动画:TranslateAnimation、ScaleAnimation、AlphaAnimation、RotateAnimation。使用方式如下所示:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"----动画集合,对应AnimationSet类
android:shareInterpolator="true"----动画集合内的动画是否共用插值器
android:duration="500"----动画时间
android:fillAfter="true"------动画结束后是否保持动画结束后的状态>
<translate---------平移动画,对应TranslateAnimation
android:fromXDelta="0"-----移动起始点的x坐标,相对于View左边界的距离
android:fromYDelta="0"-----移动起始点的y坐标,相对于View上边界的距离
android:toXDelta="100"-----移动结束点的x坐标,相对于View左边界的距离
android:toYDelta="100"-----移动结束点的y坐标,相对于View上边界的距离
/>
<!--translate动画的四个属性数据类型均为float或者percent,有三种表现形式:
1、相对于View的左/上边距,单位为像素值(如"10")
2、相对于View的左/上边距与View宽/高度的百分比(如"5%")
3、相对于View的左/上边距与View父容器的宽/高度的百分比(如"5%p")-->
<rotate------旋转动画,对应RotateAnimation
android:fromDegrees="0"----旋转的初始角度(float)
android:pivotX="0.5"----旋转中心点x坐标(float、percent),表现形式同平移动画属性
android:pivotY="0.5"----旋转中心点y坐标(float、percent),表现形式同平移动画属性
android:toDegrees="360"----旋转的结束角度(float)
/>
<scale----缩放动画,对应ScaleAnimation
android:fromXScale="1"----水平方向缩放比初始值(float),1表示原始大小
android:fromYScale="1"----竖直方向缩放比初始值(float),1表示原始大小
android:pivotX="0.5"----缩放中心点x坐标(float)
android:pivotY="0.5"----缩放中心点y坐标(float)
android:toXScale="1.5"----水平方向缩放比最终值(float)
android:toYScale="1.5"----竖直方向缩放比最终值(float)
/>
<alpha----透明度动画,对应AlphaAnimation
android:fromAlpha="1"----动画初始透明度(float),1为不透明,0为完全透明
android:toAlpha="0"----动画最终透明度(float)
/>
</set>
然后在代码中通过如下方式即可实现动画效果:
ImageView imageView=findViewById(R.id.iv_animate_view);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.view_anim);
imageView.setAnimation(animation);
animation.start();
当然,也可以在代码中使用View动画,但对于View动画来说,建议采用XML的方式来定义动画。
//在代码中使用View动画
AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
alphaAnimation.setFillAfter(true);
alphaAnimation.setDuration(1000);
imageView.setAnimation(alphaAnimation);
alphaAnimation.start();
另外,通过Animation的setAnimationListener方法可以给View动画添加监听:
public static interface AnimationListener {
void onAnimationStart(Animation animation);
void onAnimationEnd(Animation animation);
void onAnimationRepeat(Animation animation);
}
View动画的特殊使用场景
使用LayoutAnimation为ViewGroup的子View添加入场动画
在xml中定义LayoutAnimation
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/slide_from_right"----为元素指定具体的入场动画
android:animationOrder="normal"----元素动画的顺序,normal表示顺序显示,reverse表示反序显示,random表示随机显示
android:delay="10%" ----表示子元素开始动画的时间延迟
/>
LayoutAnimation在代码中可以通过下面代码的方式进行使用
LayoutAnimationController layoutAnimationController =
AnimationUtils.loadLayoutAnimation(this, R.anim.layout_animation_slide_from_right);
recyclerView.setLayoutAnimation(layoutAnimationController);
也可以在xml文件中进行使用,代码如下
<android.support.v7.widget.RecyclerView
android:id="@+id/rlv_layout_anim"
android:layoutAnimation="@anim/layout_animation_slide_from_right"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Activity的切换效果
Activity可以通过overridePendingTransiton(int enterAnim , int exitAnim)方法来自定义Activity的切换动画,这个方法必须在startActivity(intent)方法或者finish()方法之后被调用才能生效,其中enterAnim表示Activity被打开时的动画资源,exitAnim表示Activity退出时的动画资源。Fragment也可以通过setCustomerAnimations()的方法来添加切换动画。
drawable动画(帧动画)
帧动画是一组图片按照一定的顺序和时间间隔逐张切换的动画,不同于补间动画,帧动画的xml文件是放在drawable文件夹下的,其用法如下所示:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true"---是否播放一次,true表示播放一次,false表示循环播放>
<item
android:drawable="@drawable/bao1"---对应帧的资源图片
android:duration="300"---对应帧的显示时间 />
<item
android:drawable="@drawable/bao2"
android:duration="300" />
<item
android:drawable="@drawable/bao3"
android:duration="300" />
<item
android:drawable="@drawable/bao4"
android:duration="300" />
<item
android:drawable="@drawable/bao5"
android:duration="300" />
<item
android:drawable="@drawable/bao6"
android:duration="300" />
<item
android:drawable="@drawable/bao7"
android:duration="300" />
<item
android:drawable="@drawable/bao8"
android:duration="300" />
</animation-list>
然后可以在代码中使用:
imageView.setImageResource(R.drawable.drawable_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
当然,也可已在代码中定义帧动画,代码如下:
AnimationDrawable animationDrawable1=new AnimationDrawable();
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao1),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao2),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao3),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao4),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao5),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao6),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao7),50);
animationDrawable1.addFrame(getResources().getDrawable(R.drawable.bao8),50);
animationDrawable1.setOneShot(false);
imageView.setImageDrawable(animationDrawable1);
animationDrawable1.start();
在使用帧动画的时候要特别注意内存溢出的问题,因此,在使用帧动画的时候应当尽量避免使用过多尺寸较大的图片。
属性动画
属性动画不仅可以作用于View,它可以对任何对象做动画,甚至可以没有对象。在这里,需要知道一些属性动画中插值器(Interpolator)与估值器(TypeEvaluator)的相关知识。
- TimeInterpolator(时间插值器):它的作用是根据时间流逝的百分比计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速)、AccelerateDecelerateInterpolator(加速减速插值器)和DecelerateInterpolator(减速插值器)等。
- TypeEvaluator(类型估值器):它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)、和ArgbEvaluator(针对Color属性)。
在xml中定义属性动画:
<?xml version="1.0" encoding="utf-8"?>
<set ----对应AnimatorSet
xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together"----表示集合中子动画的播放次序,together表示同时播放,sequentially表示次序播放
>
<objectAnimator----对应ObjectAnimator
android:propertyName="x"----表示作用对象的属性名称,string
android:duration="300"----表示动画时长,int
android:valueFrom="0"----表示属性起始值,int|float|color
android:valueTo="200"----表示属性结束值,int|float|color
android:startOffset="0"----表示动画延迟多少毫秒后开始播放,int
android:repeatCount="0"----表示动画重复次数,默认为0,-1表示无限循环,int
android:repeatMode="restart"----表示动画的重复模式,restart表示连续重复,reverse表示逆向重复
android:valueType="intType"----表示属性的类型,有intType和floatType两个选项,若为颜色属性则无需指定,系统会自动处理
/>
<animator----对应ValueAnimator,对应属性同objectAnimator,为objectAnimator直接父类,无propertyName属性
android:duration="300"
android:valueFrom="0"
android:valueTo="200"
android:startOffset="0"
android:repeatCount="1"
android:repeatMode="restart"
android:valueType="intType" />
</set>
可以在代码中通过如下方式使用上面的属性动画:
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.property_anim);
animatorSet.setTarget(iv);
animatorSet.start();
也可以在代码中动态创建使用属性动画,代码如下:
ObjectAnimator objectAnimator=
ObjectAnimator.ofInt(iv,"x",0,200).setDuration(1000);
objectAnimator.start();
对任意属性做动画
对object的属性做动画,需要同时满足两个条件:
-
object必须要提供setAbc方法,如果动画的时候没有传递初始值,那么还要提供getAbc方法,因为系统要去取abc属性的初始值(如果这条不满足,程序直接crash)。
-
object的setAbc 对属性abc所做的改变必须能够通过某种方法反映出来,比如会带来ui改变之类的(如果这条不满足,动画无效但不会crash)。
当动画无法满足上述条件时,动画无法生效,此时有如下三种解决方法: -
如果你有权限的话,给你的对象加上get和set方法。
-
用一个类来包装原始对象,间接为其提供get和set方法。
ViewWrapper wrapper = new ViewWrapper(iv);
ObjectAnimator objectAnimator =
ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(1000);
objectAnimator.start();
private static class ViewWrapper {
private View view;
public ViewWrapper(View view) {
this.view = view;
}
public int getWidth() {
return view.getLayoutParams().width;
}
public void setWidth(int width) {
view.getLayoutParams().width = width;
view.requestLayout();
}
}
- 采用ValueAnimator,监听动画过程,自己实现属性的改变
private void performAnimate(final View target, final int start, final int end) {
//持有一个IntEvaluator对象,方便下面估值使用
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private IntEvaluator intEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获得当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = animation.getAnimatedFraction();
//直接调用整型估值器,通过比例计算出宽度,然后设置给Button
target.getLayoutParams().width = intEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
属性动画常用的特殊场景
属性动画可以为ViewGroup的子View的显示和隐藏设置过渡动画。Android系统中已经提供了默认过渡动画(在layout文件中将ViewGroup的animaiteLayoutChanges属性打开就可以使用系统提供的默认过渡动画)。Android系统中提供了如下所示的4种类型的过渡动画:
- APPERING——当通过设置子View的可见性为VISIBLE或者通过addView方法添加子View来显示子View时,子View就会执行该类型的动画。
- DISAPEARING——通过设置子View的可见性为GONE或者通过removeView方法移除子View时,子View会执行该类型动画。
- CHANGE_APPEARING——当显示子View时,所有的兄弟view就会依次执行该类型动画,且兄弟View之间执行动画间隙默认为0毫秒,然后才会执行显示子View的动画。该类型动画的周期为300毫秒,默认延迟为0毫秒。
- CHANGE_DISAPERING——当隐藏子View的动画执行完毕后,所有的兄弟View就会依次执行该类型动画且兄弟View之间执行动画间隙默认为0毫秒。该类型动画的周期为300毫秒,默认延迟为300毫秒。
若觉得Android系统提供的过渡动画不够炫,也可以自定义过渡动画:
LayoutTransition transition = new LayoutTransition();
//当多个子View要执行同一个类型的动画时,就可以通过该方法来设置子View之间执行动画的间隙默认为0毫秒。
transition.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
//为指定类型的过渡动画设置执行动画的周期,默认为300毫秒。
transition.setDuration(LayoutTransition.CHANGE_APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
//为指定类型的过渡动画设置延迟执行的时间,默认与过渡动画的类型相关
transition.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
ObjectAnimator appearingAnimator = ObjectAnimator.ofPropertyValuesHolder((Object) null,
PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("alpha", 0.0f, 1.0f));
transition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING));
transition.setStartDelay(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
ObjectAnimator disappearingAnimator = ObjectAnimator.ofPropertyValuesHolder((Object) null,
PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("alpha", 1.0f, 0));
transition.setAnimator(LayoutTransition.DISAPPEARING, disappearingAnimator);
transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
transition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
//为ViewGroup设置过渡动画。
llImage.setLayoutTransition(transition);
参考资料:
- 《Android开发艺术探索》
- Android中的View动画和属性动画