美文网首页动画
Android动画——View动画

Android动画——View动画

作者: 何小送 | 来源:发表于2020-01-08 11:32 被阅读0次

    一.View动画的介绍

    Android的动画分为两种:View动画(帧动画也属于View动画),属性动画。

    View动画的作用对象是View,它支持4种动画效果:平移动画,缩放动画,旋转动画,透明度动画。帧动画也属于View动画,但帧动画的表现形式和上面的四种变换效果不太一样。

    本文将介绍:

    • View动画的四种类型以及动画集合set
    • View动画的使用
    • View动画的监听
    • 自定义View动画
    • 帧动画
    • View动画的特殊使用场景

    二.View动画的种类

    View动画四种变换效果对应着Animation的四个子类:

    • TranslateAnimation(平移动画,<translate>)
    • ScaleAnimation(缩放动画,<scale>)
    • RotateAnimation(旋转动画,<rotate>)
    • AlphaAnimation(透明度动画<alpha>)。

    这四种动画既可以通过XML来定义,也可以通过代码来动态创建。对于View动画来说,建议采用XML来定义动画,因为XML格式的动画可读性更好。

    View动画的XML格式的文件路径为:res/anim/**.xml。

    三.View动画的四种类型的xml格式基本属性

    所有value值都为float类型。

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="500"
        android:repeatMode="reverse"
        android:shareInterpolator="true">
    
        <translate
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:toXDelta="300"
            android:toYDelta="300" />
    
        <alpha
            android:fromAlpha="0.1" 
            android:toAlpha="1.0" />
    
        <scale
            android:fromXScale="1.0"
            android:fromYScale="0.5"
            android:pivotX="10"
            android:pivotY="10"
            android:toXScale="1.5"
            android:toYScale="1.5" />
    
        <rotate
            android:fromDegrees="0"
            android:pivotX="10"
            android:pivotY="10"
            android:toDegrees="180" />
    </set>
    
    1.动画集合set

    对应AnimationSet类,可以包含若干个动画,并且它的内部也是可以嵌套其他动画集合的

    • android:interpolator:表示动画集合所采用的插值器,插值器影响动画的速度,比如非匀速动画就需要通过插值器来控制动画的播放过程。该属性可以不指定,默认为@android:anim/accelerate_decelerate_interpolator,即加速减速插值器。
    • android:shareInterpolator:表示集合中的动画是否和集合共享同一个插值器。如果不指定插值器,那么子动画就需要单独指定所需的插值器或者使用默认值。
    2.1 平移动画translate

    对应TranslateAnimation类,View在水平和竖直方向的平移

    • android:fromXDelt:表示x的起始值
    • android:fromYDelt:表示y的起始值
    • android:toXDelta:表示x的结束值
    • android:toYDelta:表示y的结束值
    2.2透明度动画alpha

    对应AlphaAnimation类,改变View的透明度

    • android:fromAlpha:表示透明度的起始值,比如0.1
    • android:toAlpha:表示透明度的结束值,比如1
    2.3缩放动画scale

    对应ScaleAnimation类,使View具有放大和缩小的动画效果

    • android:fromXScale:水平方向缩放的起始值
    • android:fromYScale:竖直方向缩放的起始值
    • android:pivotX:缩放的轴点x坐标,会影响缩放的效果
    • android:pivotY:缩放的轴点y坐标,会影响缩放的效果
    • android:toXScale:水平方向的结束值
    • android:toYScale:竖直方向的结束值
    2.4旋转动画rotate

    对应RotateAnimation类,使View具有旋转的动画效果

    • android:fromDegrees:旋转开始的角度
    • android:pivotX:旋转的轴点x坐标
    • android:pivotY:旋转的轴点y坐标
    • android:toDegrees:旋转结束的角度
    View动画还有一些常用的属性:
    • android:duration:动画的持续时间;
    • android:fillAfter:动画结束以后View是否停留在结束位置,true表示View停留在结束位置,false则不停留。

    四.View 动画的使用

    1.使用xml格式定义View动画
    TextView tv = findViewById(R.id.tv);
    Animation animation = AnimationUtils.loadAnimation(this,R.anim.animation_tv);
    tv.startAnimation(animation);
    
    2.使用通过代码创建的View 动画
    /**这里写一个透明度动画,其他类型动画写法类似*/
    AlphaAniamation alphaAnimation = new AlphaAnimation(0,1);//透明度由0到1
    alphaAnimation.setDuration(300);//动画时间300ms
    tv.startAnimation(alphaAnimation);
    

    五.View 动画的监听

    通过Animation的setAnimationListener给View动画添加过程监听。

        public static interface AnimationListener {
            void onAnimationStart(Animation animation);
            void onAnimationEnd(Animation animation);
            void onAnimationRepeat(Animation animation);
        }
    

    六.自定义View 动画

    自定义view动画既简单又复杂。简单是因为只需继承Animation这个抽象类,然后重写initialize和applyTransformation方法就好了,在initialize方法中做一些初始化工作,在applyTransformation中进行相应的矩阵变换即可,里面经常需要采用Camera来简化矩阵变换的过程。复杂是因为自定义view动画的过程主要是矩阵变换的过程,需要有线性代数的功底。

    我们就来个例子吧,谷歌 APIDemo 里的自定义3d动画Rotate3dAnimation。围绕y轴旋转并且同时沿着z轴平移从而实现类似于3d的效果。先上效果图,效果图如下。

    QQ图片20200107153625.gif

    代码量很少,如下图。

    public class Rotate3dAnimation extends Animation {
        private final float mFromDegrees;
        private final float mToDegrees;
        private final float mCenterX;
        private final float mCenterY;
        private final float mDepthZ;
        private final boolean mReverse;
        private Camera mCamera;
        float scale = 1;    // <------- 像素密度
    
        /**
         * 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
         * @param context     <------- 添加上下文,为获取像素密度准备
         * @param fromDegrees 起始时角度
         * @param toDegrees   结束时角度
         * @param centerX     旋转中心x坐标
         * @param centerY     旋转中心y坐标
         * @param depthZ      最远到达的z轴坐标
         * @param reverse     true 表示由从0到depthZ,false相反
         */
        public Rotate3dAnimation(Context context, float fromDegrees, float toDegrees,
                                 float centerX, float centerY, float depthZ, boolean reverse) {
            mFromDegrees = fromDegrees;
            mToDegrees = toDegrees;
            mCenterX = centerX;
            mCenterY = centerY;
            mDepthZ = depthZ;
            mReverse = reverse;
    
            // 获取手机像素密度 (即dp与px的比例)
            scale = context.getResources().getDisplayMetrics().density;
        }
    
        @Override
        public void initialize(int width, int height, int parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mCamera = new Camera();
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final float fromDegrees = mFromDegrees;
            float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
            final float centerX = mCenterX;
            final float centerY = mCenterY;
            final Camera camera = mCamera;
            final Matrix matrix = t.getMatrix();
            camera.save();
    
            // 调节深度
            if (mReverse) {
                camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
            } else {
                camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
            }
    
            // 绕y轴旋转
            camera.rotateY(degrees);
    
            camera.getMatrix(matrix);
            camera.restore();
    
            // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
            float[] mValues = new float[9];
            matrix.getValues(mValues);              //获取数值
            mValues[6] = mValues[6]/scale;          //数值修正
            mValues[7] = mValues[7]/scale;          //数值修正
            matrix.setValues(mValues);              //重新赋值
    
            // 调节中心点
            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
        }
    }
    
    

    使用:我这里是在fragment里写的,布局文件这里没贴出来,因为就是一个简单的ImageView。

            ImageView imageView = view.findViewById(R.id.iv);
    
            //括号内参数分别为(上下文,开始角度,结束角度,x轴中心点,y轴中心点,深度,是否扭曲)
            final Rotate3dAnimation rotation = new Rotate3dAnimation(Objects.requireNonNull(getContext()),
                    0, 360, 150, 75, 0f, true);
    
            rotation.setDuration(3000);                         //设置动画时长
            rotation.setRepeatCount(5);                         //设置重复次数
            rotation.setFillAfter(true);                        //保持旋转后效果
            rotation.setInterpolator(new LinearInterpolator());    //设置插值器
            imageView.startAnimation(rotation);
    

    七.帧动画

    帧动画也是属于View动画。帧动画是顺序播放一组预先定义好的图片。系统提供了单独一个类AnimationDrawable来使用帧动画。帧动画使用比较简单,通过XML来定义一个AnimationDrawable,其地址为:res/drawable/***.xml。

    在drawable目录下新建一个以根节点为animaion-list的xml文件。一个item对应一帧图片。android:oneshot="true",只播放一次,android:oneshot="false"无限循环,如果不设置则值默认为false无限循环。代码如下图所示。

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
    
        <item
            android:drawable="@drawable/img1"
            android:duration="500" />
        <item
            android:drawable="@drawable/img2"
            android:duration="500" />
        <item
            android:drawable="@drawable/img3"
            android:duration="500" />
    
    </animation-list>
    

    将上述的drawable作为View的背景并通过Draw able来播放动画即可。使用如下图。

            View v = findViewById(R.id.iv);
            v.setBackgroundResource(R.drawable.animation_frame);
            AnimationDrawable animationDrawable = (AnimationDrawable) v.getBackground();
            animationDrawable.start();
    

    帧动画使用简单,但是注意图片不要太大,否则容易引起OOM。

    八.View动画的特殊使用场景

    View动画除了上面介绍的四种以外,还可以在一些特殊的场景下使用,比如:

    • 在ViewGroup中控制子元素的出场效果。
    • 在Activity中实现不同Activity之间的切换。
    1.ViewGroup中控制子元素的出场效果——LayoutAnimation

    LayoutAnimaton作用于ViewGroup,为View Group指定一个动画,这样当它的子元素出场时都会具有这种动画效果。
    LayoutAnimaton有四个属性:animationOrder,animation,delay,interpolator。

    • animationOrder:有三个选项:normal,reverse,random。normal表示顺序显示(即排在前面的子元素先开始播放入场动画),reverse表示逆向显示(即排在后面的子元素先开始播放入场动画),randow表示随机播放入场动画。
    • animation:为子元素指定具体的入场动画。
    • delay:表示子元素开始动画的时间延迟。即delay=第一个子元素动画时间/第二个子元素动画时间。怎么理解呢,打个比方,如果delay的值为0.5,那么第一个子元素动画执行到一半的时候,第二个子元素动画开始;如果delay的值为1,那么第一个子元素动画执行完后才开始紧接着执行;
    • interpolator:插值器,控制动画变化的速率,不写则默认为是加速减速插值器。

    我们有个经典的例子——RecycleView的item都以一定的动画的形式出现。我们先上效果图。

    QQ图片20200107183900.gif

    我们现在就开始写RecycleView的item的动画啦,关键步骤和代码如下:

    1.在res/anim目录中新建一个根节点为set的anim_recycle_view_item.xml文件,这里将其作为子元素入场动画(每个Item的动画),代码如下图。

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fillAfter="false"
        android:shareInterpolator="true">
    
        <alpha
            android:fromAlpha="0.0"
            android:toAlpha="1.0" />
    
        <translate
            android:fromXDelta="-500"
            android:toXDelta="0" />
    
    </set>
    

    2.在res/anim目录中新建一个根节点为layoutAnimation 的anim_recycle_view.xml文件,在里面引用步骤1写好的子元素动画即可。代码如下图。

    <?xml version="1.0" encoding="utf-8"?>
    <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:animation="@anim/anim_recycle_view_item"
        android:animationOrder="normal"
        android:delay="0.5">
    
    </layoutAnimation>
    

    3.给RecycleView添加layoutAnimation有2种方式,布局中添加或者java代码添加。

    • 方式一:在布局文件中对RecycleView添加layoutAnimation属性,引用步骤2写好的layoutAnimation即可,代码如下:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ebf2fa"
        android:orientation="vertical">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView"
            android:layout_width="match_parent"
            android:layoutAnimation="@anim/anim_recycle_view"
            android:layout_height="match_parent"
            android:padding="5dip" />
    
    
    </LinearLayout>
    
    • 方式二:在java代码中对RecycleView添加layoutAnimation属性,引用步骤2写好的layoutAnimation即可,代码如下:
            RecyclerView recyclerView=findViewById(R.id.recycleView);
            Animation animation= AnimationUtils.loadAnimation(this,R.anim.recycle_view);
            LayoutAnimationController controller=new LayoutAnimationController(animation);
            controller.setDelay(0.5f);
            controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
            recyclerView.setLayoutAnimation(controller);
    

    4.其它代码就是正常的RecycleView的使用了,比如java代码和item的布局代码这里就不贴啦。现在运行一下,就可以看见跟效果图的一样的动画啦。

    2.Activity的切换效果

    Activity是有默认的切换效果,我们也可以自定义这个Activity的切换效果,主要用到overridePendingTransition(int enterAnim,int exitAnim)这个方法,但是该方法必须写在在startActivity(Intent intent)或者finish()之后才能生效,不然动画效果将不起作用。

    • enterAnim——Activity被打开时,所需要的动画资源id。
    • exitAnim——Activity被暂停时所需要的动画资源id。

    启动Activity时添加自定义的切换效果,代码如下:

    Intent intent = new Intent(this, DetailActivity.class);
    startActivity(intent);
    overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
    

    退出Activity时添加自定义的切换效果,代码如下:

        @Override
        public void finish() {
            super.finish();
            overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
        }
    

    小结:Android View动画的所有知识都在这里了。这是看完《Android开发艺术探索》做的笔记与一些思考感悟。

    相关文章

      网友评论

        本文标题:Android动画——View动画

        本文链接:https://www.haomeiwen.com/subject/digyoctx.html