动画

Android动画——View动画

2020-01-08  本文已影响0人  何小送

一.View动画的介绍

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

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

本文将介绍:

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

二.View动画的种类

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

这四种动画既可以通过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。

我们有个经典的例子——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代码添加。

<?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>
        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开发艺术探索》做的笔记与一些思考感悟。

上一篇下一篇

猜你喜欢

热点阅读