Android动画系列(2)—补间动画

首语

  • 这是Android动画系列的目录,有兴趣的可以学习:Android动画

补间动画

补间动画指的是做FLASH动画时,在两个关键帧中间需要做“补间动画”,才能实现图画的运动;插入补间动画后两个关键帧之间的插补帧是由计算机自动运算而得到的。
实际上,Android 的补间动画也是由我们指定动画开始、动画结束2个关键点,中间部分的动画由系统完成。

  • 补间动画又叫View动画。上一章的帧动画和补间动画都属于视图动画。View动画的作用对象是View,它支持四种动画效果,分别为平移动画、缩放动画、旋转动画和透明度动画。同时也就对应着Animation的四个子类:TranslateAnimationScaleAnimationRotateAnimationAlphaAnimation。具体如下表所示。
名称标签子类效果
平移动画<translate>TranslateAnimation移动View
缩放动画<scale>ScaleAnimation放大或缩小View
旋转动画<rotate>RotateAnimation旋转View
透明度动画<alpha>AlphaAnimation改变View的透明度
  • 补间动画可以通过两种方式实现,XML实现和代码实现。建议采用XML来实现,因为XML格式的动画可读性更好。

插值器

  • 在动画实现之前,了解一下插值器的知识。插值器用来控制动画的变化速度,可以理解成动画渲染器,当然我们也可以自己实现Interpolator 接口,自行来控制动画的变化速度,而Android中已经为我们提供了五个可供选择的实现类。
    • LinearInterpolator:动画以均匀的速度改变
    • AccelerateInterpolator:在动画开始的地方改变速度较慢,然后开始加速
    • AccelerateDecelerateInterpolator:在动画开始、结束的地方改变速度较慢,中间时加速
    • CycleInterpolator:动画循环播放特定次数,变化速度按正弦曲线改变: Math.sin(2 * mCycles * Math.PI * input)
    • DecelerateInterpolator:在动画开始的地方改变速度较快,然后开始减速
    • AnticipateInterpolator:反向,先向相反方向改变一段再加速播放
    • AnticipateOvershootInterpolator:开始的时候向后然后向前甩一定值后返回最后的值
    • BounceInterpolator: 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
    • OvershottInterpolator:回弹,最后超出目的值然后缓慢改变到目的值
  • XML实现中,属性是:android:interpolator, 而上面对应的值是:@android:anim/linear_interpolator,其实就是驼峰命名法变下划线而已 AccelerateDecelerateInterpolator对应:@android:anim/accelerate_decelerate_interpolator
XML实现
  • 补间动画的XML文件位置在res/anim目录中。
平移动画
	<!--fromXDelta/fromYDelta:动画起始位置的X/Y坐标。-->
    <!--toXDelta/toYDelta:动画结束位置的X/Y坐标。-->
    <!--duration:动画播放的速度。-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
    android:fromXDelta="0"  
    android:toXDelta="320"  
    android:fromYDelta="0"  
    android:toYDelta="0"  
    android:duration="2000"/>
缩放动画
	<!--fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例。-->
    <!--toXScale/toYScale:沿着X轴/Y轴缩放的结束比例。-->
    <!--pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的 中心为中轴点。-->
<scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_interpolator"  
    android:fromXScale="0.2"  
    android:toXScale="1.5"  
    android:fromYScale="0.2"  
    android:toYScale="1.5"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:duration="2000"/>
旋转动画
	<!--fromDegrees/toDegrees:旋转的起始/结束角度。-->
    <!--repeatCount:旋转的次数,默认值为0,代表一次,假如是其他值,比如3,则旋转4次 另外,值为-1或者infinite时,表示动画永不停止。-->
    <!--repeatMode:设置重复模式,默认restart,但只有当repeatCount大于0或者infinite或-1时 才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动。-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
    android:fromDegrees="0"  
    android:toDegrees="360"  
    android:duration="1000"  
    android:repeatCount="1"  
    android:repeatMode="reverse"/> 
透明度动画
	<!--fromAlpha :起始透明度。-->
    <!--toAlpha:结束透明度。-->
    <!--透明度的范围为:0-1,完全透明-完全不透明。-->
<alpha xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
    android:fromAlpha="1.0"  
    android:toAlpha="0.1"  
    android:duration="2000"/>
动画组合
<!--<set>标签表示动画集合,对应AnimationSet类,它可以包含若干动画。-->
<!-- android:shareInterpolator 表示集合中的动画是否和集合共享一个插值器,如果集合不指定插值器,那么子动画就需要单独指定所需的插值器或者使用默认值-->
<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/decelerate_interpolator"  
    android:shareInterpolator="true" >  
  
    <scale  
        android:duration="2000"  
        android:fromXScale="0.2"  
        android:fromYScale="0.2"  
        android:pivotX="50%"  
        android:pivotY="50%"  
        android:toXScale="1.5"  
        android:toYScale="1.5" />  
  
    <rotate  
        android:duration="1000"  
        android:fromDegrees="0"  
        android:repeatCount="1"  
        android:repeatMode="reverse"  
        android:toDegrees="360" />  
  
    <translate  
        android:duration="2000"  
        android:fromXDelta="0"  
        android:fromYDelta="0"  
        android:toXDelta="320"  
        android:toYDelta="0" />  
  
    <alpha  
        android:duration="2000"  
        android:fromAlpha="1.0"  
        android:toAlpha="0.1" />  

</set>  
代码调用
Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
imageView.startAnimation(alphaAnimation);
代码实现
平移动画
//Animation.RELATIVE_TO_SELF 相当于自身
// Animation.RELATIVE_TO_PARENT 相当于屏幕
 TranslateAnimation  translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
                -1, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 1);
        translateAnimation.setDuration(2000);
        translateAnimation.setRepeatCount(1);//重复次数
        translateAnimation.setRepeatMode(Animation.RESTART);//重复模式
        translateAnimation.setFillAfter(true);//是否填充在结束的位置上
        tweeniv.startAnimation(translateAnimation);
缩放动画
  ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 2, 0.1f, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setRepeatCount(1);
        scaleAnimation.setRepeatCount(Animation.REVERSE);
        scaleAnimation.setDuration(2000);
        scaleAnimation.setFillAfter(true);//填充动画的结束位置
        tweeniv.startAnimation(scaleAnimation);
旋转动画
 RotateAnimation rotateAnimation = new RotateAnimation(20, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setDuration(2000);
        rotateAnimation.setRepeatCount(1);
        rotateAnimation.setRepeatMode(Animation.REVERSE);
        tweeniv.startAnimation(rotateAnimation);
透明度动画
AlphaAnimation  alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setRepeatCount(1);
        alphaAnimation.setDuration(2000);
        tweeniv.startAnimation(alphaAnimation);
动画组合
AnimationSet animationSet = new AnimationSet(false);//false表示使用动画的校对器,true表示使用集合的校对器
        animationSet.setDuration(2000);
        translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
                -1, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 1);
        rotateAnimation = new RotateAnimation(20, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        alphaAnimation = new AlphaAnimation(0, 1);
        scaleAnimation = new ScaleAnimation(0.5f, 2, 0.1f, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        
        animationSet.addAnimation(translateAnimation);
        animationSet.addAnimation(scaleAnimation);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(rotateAnimation);
        tweeniv.startAnimation(animationSet);

动画监听

//translateAnimation 动画对象
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            //动画开始
            }

            @Override
            public void onAnimationEnd(Animation animation) {
            //动画结束
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            //动画重复
            }
        });

自定义View动画

  • 我们派生出一种新动画只需要集成Animation这个抽象类,然后重写它的initializeapplyTransformation方法,在initialize中做一些初始化工作。在applyTransformation中进行相应的矩阵变换即可。因为自定义View动画的过程主要是矩阵变换过程。
	public RotateAnimation() {
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
    }


    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
    }

View动画的特殊使用场景

LayoutAnimation
  • LayoutAnimation作用于ViewGroup,为ViewGroup指定一个动画,这样它的子元素出场都会具有这种动画效果。例如ListView每个item都以一定的动画形式出现就是使用LayoutAnimation
使用步骤
  1. 定义LayoutAnimation
<!--目录:res/anim/-->
<!--android:delay表示子元素开始动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5表示每个子元素都需要延迟150ms才能播放入场动画。
总体来说,第一一个子元素延迟150ms开始播放入场动画,第2个子元素延迟300ms开始播放入场动画,依次类推。-->
<!--android:animationOrder表示子元素动画的顺序,有三种选项:normal(顺序显示),reverse(逆向显示),random(随机显示)。-->
<!--android:animation为子元素指定具体的动画-->
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/anim_item"
    android:animationOrder="normal"
    android:delay="0.5"/>
  1. 为子元素指定具体动画
<!--目录:res/anim/-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:shareInterpolator="true">

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

    <translate
        android:fromXDelta="500"
        android:toXDelta="0" />

</set>
  1. ViewGroup指定android:layoutAnimation
<ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/anim_layout"
        android:divider="@color/colorAccent"
        android:cacheColorHint="@color/colorPrimaryDark"
        android:listSelector="@color/colorAccent"
        />

补充: 除了在XML中指定android:layoutAnimation,还可以通过LayoutAnimationController来实现。

		ListView listView=(ListView) layout.findViewById(R.id.list);
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
        LayoutAnimationController controller = new LayoutAnimationController(animation);
        controller.setDelay(0.5f);
        controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
        listView.setLayoutAnimation(controller);
Activity的切换效果
  • Activity有默认的切换效果,我们自定义效果可以通过overridePendingTransition(int enterAnim, int exitAnim)方法,这个方法必须在startActivity();或finish()之后调用才有效。
		Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        //参数一:新Activity进场时的动画;参数二:旧Activity退场时的动画
        overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
Fragment的过渡动画
  • 我们可以调用FragmentTransaction对象的setTransition(int transit)Fragment指定标准的过场动画,transit的可选值如下:
    • TRANSIT_NONE:无动画
    • TRANSIT_FRAGMENT_OPEN:打开形式的动画
    • TRANSIT_FRAGMENT_CLOSE:关闭形式的动画
 		FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
        fragmentTransaction.setTransition(TRANSIT_NONE);
  • 上面的标准过程动画是两个都可以调用的,而不同的地方则在于自定义转场动setCustomAnimations()方法!
    • app包下的FragmentsetCustomAnimations(int enter, int exit, int popEnter, int popExit) 分别是添加,移除,入栈,以及出栈时的动画! 另外要注意一点的是,对应的动画类型是:属性动画(Property),就是动画文件 的根标签要是:<objectAnimator><valueAnimator>或者是前面两者放到一个里;
    • v4包下的Fragment: v4包下的则支持两种setCustomAnimations()
		FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction =fragmentManager.beginTransaction();
        fragmentTransaction.setCustomAnimations(R.anim.push_right_in,R.anim.push_right_out,R.anim.push_left_in,R.anim.push_left_out);//设置进入,退出动画
  • 注意: 要在fragmentTransaction addreplacecommit方法前设置动画,否则动画将不会运行。
  • 我们自定义好动画后,有时候需要判断动画是否开始、结束,这时需要对动画状态进行监听,我们重写Fragment中的onCreateAnimationonCreateAnimator方法
  • Fragment v4
    public Animation onCreateAnimation(int transit,boolean enter,int nextAnim)
  • Fragment app
    public Animator onCreateAnimator(int transit,boolean enter,int nextAnim)

本文由 八归少年 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
原文链接: https://www.yanghujun.com/archives/gapanimation
最后更新于:Jun 30, 2020 9:06:52 PM

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×