View 动画

动画分类

Android动画总体分为两类:View动画 和 Android3.0 之后出现的属性动画
View动画又分为两类:帧动画(Frame Animation)和补间动画(Tweened Animation)。

View动画

1. 帧动画

帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。
这里写图片描述
如上图,就是把一幅幅的图片按顺序显示,造成动画的视觉效果。
实现:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame_animation);
        ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
        animationImg1.setImageResource(R.drawable.frame_anim1);
        AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
        animationDrawable1.start();
    }

2. 补间动画

补间动画分为四种形式:translate(位移)、rotate(旋转)、scale(缩放大小)、alpha(淡入淡出)
补间动画有两种实现方式:xml文件形式和代码形式。

1、前者优点:动画描述可读性更好
2、后者优点:动画效果可动态创建

2.1 位移

xml 形式:
translate.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">
     <!--
        位移
        android:fillBefore = “true” 动画播放完后,视图是否会停留在动画开始的状态,默认为true
        android:fillAfter = “false” 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
        android:fillEnabled= “true” 是否应用fillBefore值,对fillAfter值无影响,默认为true
        android:repeatMode= “restart” 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
        android:repeatCount = “0” 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
        android:interpolator = @[package:]anim/interpolator_resource 插值器,即影响动画的播放速度,下面会详细讲  -->

    <translate
        android:duration="2000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="600"
        android:toYDelta="600"
        android:interpolator="@android:anim/linear_interpolator"
        android:repeatMode="restart"
        android:repeatCount="infinite"/>
</set>

详解插值器

说明 代码中方法 xml中属性
越来越快 AccelerateInterpolator() @android:anim/accelerate_interpolator
越来越慢 DecelerateInterpolator() @android:anim/decelerate_interpolator
先快后慢 AccelerateDecelerateInterpolator() @android:anim/accelerate_decelerate_interpolator
先后退一小步然后向前加速 AnticipateInterpolator() @android:anim/anticipate_interpolator
快速到达终点超出一小步然后回到终点 OvershootInterpolator() @android:anim/overshoot_interpolator
到达终点超出一小步然后回到终点 AnticipateOvershootInterpolator() @android:anim/anticipate_overshoot_interpolator
弹球效果,弹几下回到终点 BounceInterpolator() @android:anim/bounce_interpolator
均匀速度 LinearInterpolator() @android:anim/linear_interpolator

在Activity中调用

Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
tvTitle.startAnimation(animation);

代码形式:

TranslateAnimation translate = new TranslateAnimation(0, 0, 0, 750);
translate.setDuration(4000);
translate.setFillAfter(true);
translate.setRepeatCount(Animation.INFINITE); //无线循环
translate.setRepeatMode(Animation.REVERSE); //倒序播放
translate.setInterpolator(new LinearInterpolator());
tvTitle.startAnimation(translate);

2.2 旋转

xml形式:
rotate.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--
         旋转
         fromDegrees  动画开始时的角度
         toDegrees    动画结束时物件的旋转角度,正代表顺时针,负代表逆时针

         pivotX pivotY,可取值为数字,百分比,或者百分比p
         设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
         设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
         设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT  -->

    <rotate
        android:duration="4000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="-360" />
</set>

在Activity中调用:

Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);
tvTitle.startAnimation(rotateAnimation);

代码形式:

// 参数说明:
// 1. fromDegrees :动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
// 2. toDegrees :动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
// 3. pivotXType:旋转轴点的x坐标的模式
// 4. pivotXValue:旋转轴点x坐标的相对值,取值范围0-1
// 5. pivotYType:旋转轴点的y坐标的模式
// 6. pivotYValue:旋转轴点y坐标的相对值,取值范围0-1

// pivotXType = Animation.ABSOLUTE:旋转轴点的x坐标 =  View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
// pivotXType = Animation.RELATIVE_TO_SELF:以自身为标准,旋转轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
// pivotXType = Animation.RELATIVE_TO_PARENT:以父组件为标准,旋转轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)

RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(4000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
tvTitle.startAnimation(rotateAnimation);

2.3 缩放大小

xml形式
scale.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--
         缩放大小
         fromXScale,fromYScale  动画开始前X,Y的缩放,0.0为不显示,  1.0为正常大小
         toXScale,toYScale      动画最终缩放的倍数, 1.0为正常大小,大于1.0放大
         startOffset             动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间 

         轴点 = 视图缩放的中心点
         pivotX pivotY,可取值为数字,百分比,或者百分比p
         设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
         设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
         设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT-->

    <scale
        android:duration="4000"
        android:fromXScale="0"
        android:fromYScale="0"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:startOffset="0"
        android:toXScale="1.5"
        android:toYScale="1.5" />
</set>

在Activity中调用:

Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
tvTitle.startAnimation(scaleAnimation);

代码形式

// 参数说明:
// 1. fromX :动画在水平方向X的结束缩放倍数
// 2. toX :动画在水平方向X的结束缩放倍数
// 3. fromY :动画开始前在竖直方向Y的起始缩放倍数
// 4. toY:动画在竖直方向Y的结束缩放倍数
// 5. pivotXType:缩放轴点的x坐标的模式
// 6. pivotXValue:缩放轴点x坐标的相对值,取值范围0-1
// 7. pivotYType:缩放轴点的y坐标的模式
// 8. pivotYValue:缩放轴点y坐标的相对值,取值范围0-1

// pivotXType = Animation.ABSOLUTE:缩放轴点的x坐标 =  View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
// pivotXType = Animation.RELATIVE_TO_SELF:以自身为标准,缩放轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
// pivotXType = Animation.RELATIVE_TO_PARENT:以父组件为标准,缩放轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)

ScaleAnimation scaleAnimation = new ScaleAnimation(1f,0.5f,1f,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(4000);
scaleAnimation.setRepeatCount(Animation.INFINITE); scaleAnimation.setRepeatMode(Animation.REVERSE);
tvTitle.startAnimation(scaleAnimation);

2.4 淡入淡出

xml形式
alpha.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--
         淡入淡出
         fromAlpha  开始时透明度,范围0-1,1:不透明;0:完全透明
         toAlpha    结束时透明度
         duration   动画持续时间  -->

    <alpha
        android:duration="4000"
        android:fromAlpha="1"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:toAlpha="0.3" />
</set>

在Activity中调用:

Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);
tvTitle.startAnimation(alphaAnimation);

代码形式:

AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1f);
alphaAnimation.setDuration(4000);
alphaAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatMode(Animation.REVERSE);
tvTitle.startAnimation(alphaAnimation);

2.5 组合动画

xml形式

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:fillAfter="true"
    android:interpolator="@android:anim/linear_interpolator"
    android:shareInterpolator="true"
    android:startOffset="1000">

 <!--
         android:shareinterpolator = “true” 组合动画独特的属性
         表示组合动画中的动画是否和集合共享同一个差值器
         如果集合不指定插值器,那么子动画需要单独设置

         android:startOffset  动画延迟开始时间(ms)
         组合动画播放时是全部动画同时开始
         如果想不同动画不同时间开始就要使用android:startOffset属性来延迟单个动画播放时间 -->

    <!-- 平移 -->
    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="600"
        android:toYDelta="700"
        android:repeatCount="infinite"
        android:repeatMode="reverse"/>

    <!-- 缩放大小 -->
    <scale
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.5"
        android:toYScale="0.5"
        android:repeatCount="infinite"
        android:repeatMode="reverse"/>

    <!-- 旋转 -->
    <!--<rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360"
        android:repeatCount="infinite"
        android:repeatMode="reverse"/>-->

    <!-- 淡入淡出 -->
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0.3"
        android:repeatCount="infinite"
        android:repeatMode="reverse"/>

</set>

在Activity中调用:

Animation zuheAnimation = AnimationUtils.loadAnimation(this, R.anim.zuhe_animation);
tvTitle.startAnimation(zuheAnimation);

代码形式

//组合动画设置
//步骤1:创建组合动画对象(设置为true)
AnimationSet animationSet = new AnimationSet(true);
//步骤2:设置组合动画的属性
animationSet.setFillAfter(true);
animationSet.setInterpolator(new LinearInterpolator());
animationSet.setDuration(4000);

//步骤3:创建子动画
//旋转动画
Animation rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
                rotate.setRepeatCount(Animation.INFINITE);
                rotate.setRepeatMode(Animation.REVERSE);

//平移动画
Animation translate01 = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, 0,
                        TranslateAnimation.RELATIVE_TO_PARENT, 0.5f,
                        TranslateAnimation.RELATIVE_TO_SELF, 0,
                        TranslateAnimation.RELATIVE_TO_SELF, 0);

//淡入淡出动画
Animation alpha = new AlphaAnimation(1, 0.2f);
alpha.setStartOffset(1000);

//缩放动画
Animation scale = new ScaleAnimation(1,0.5f,1,0.5f,
                        Animation.RELATIVE_TO_SELF, 0.5f,
                        Animation.RELATIVE_TO_SELF, 0.5f);
scale.setStartOffset(1500);

//步骤4:将创建的子动画添加到组合动画里
animationSet.addAnimation(rotate);
                animationSet.addAnimation(translate01);
                animationSet.addAnimation(alpha);
                animationSet.addAnimation(scale);

tvTitle.startAnimation(animationSet);

3. 监听动画

  • Animation类通过监听动画开始 / 结束 / 重复时刻来进行一系列操作,如跳转页面等等
  • 通过在 Java 代码里setAnimationListener()方法设置
 animationSet.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        //动画开始时执行
                        Toast.makeText(ViewAnimatorActivity.this, "动画开始了", Toast.LENGTH_SHORT).show();
                    }

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

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        //动画重复时执行

                    }
                });

4. 应用场景

4.1 标准的动画效果

  • 补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度;
  • 除了常规的动画使用,补间动画还有一些特殊的应用场景。

4.2 特殊的应用场景

  • Activity 的切换效果
  • Fragement 的切换效果
  • 视图组(ViewGroup)中子元素的出场效果

4.2.1 Activity 的切换效果

即 Activity 启动 / 退出时的动画效果。

a.启动动画

此处使用系统自带的动画效果

Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);
 //系统自带:淡入淡出动画
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
//系统自带:从左向右滑动效果
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

//特别注意
//overridePendingTransition()必须要在startActivity(intent)后被调用才能生效

//采用overridePendingTransition(int enterAnim, int exitAnim)进行设置
//enterAnim:从Activity a跳转到Activity b,进入b时的动画效果资源ID
//exitAnim:从Activity a跳转到Activity b,离开a时的动画效果资源Id
b.退出动画

此处使用系统自带的动画效果

@Override
public void finish() {
     super.finish();
     //系统自带:从左向右滑动效果
     overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

    //特别注意
    //overridePendingTransition()必须要在finish()后被调用才能生效
    }

对于参数 enterAnim & exitAnim 的资源ID,也可自定义Activity的切换效果:

此处就用到补间动画了

a. 自定义 淡入淡出 效果

淡入淡出 效果是采用透明度动画(Alpha)。
fade_in.xml(淡入)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="1500"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>

fade_out.xml(淡出)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="1500"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

在Java代码中设置

Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);
//自定义:淡入淡出动画
 overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
b. 自定义 左右滑动 效果
  • 左右滑动 效果是采用平移动画(Translate)
  • 先了解 Activity 的位置信息,如下图
    这里写图片描述

从上图可以看出:

  • 以屏幕底边为X轴,屏幕左边为Y轴;
  • 当Activity在X轴 = -100%p时,刚好完全超出屏幕到左边(位置1)
  • 当Activity在X轴 = 0%p时,刚好完全在屏幕内(位置2)
  • 当Activity在X轴 = 100%p时,刚好完全超出屏幕到右边(位置3)

下面自定义一个动画效果:从右滑到左
out_to_left.xml

从中间滑到左边,即从位置2 - 位置1

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <!--从中间滑到左边-->

    <translate
        android:duration="500"
        android:fromXDelta="0%p"
        android:toXDelta="-100%p" />
</set>

in_from_right.xml

从右边滑到中间,即从位置3 - 位置2

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <!--从右边滑到中间-->

    <translate
        android:duration="500"
        android:fromXDelta="100%p"
        android:toXDelta="0%p" />
</set>

在Java代码中设置效果

Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);

//自定义:从左向右滑动效果
overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);

效果图
这里写图片描述

  • 关于 缩放和旋转动画 作为Activity的动画效果也是类似的
  • 通过 想象力 能组合 上述4种基本动画 进行动画效果展示
  • 此处仅列出较为简单的切换效果,如想实现更多酷炫的切换动画,请看文章

4.2.2 Fragment动画切换效果

系统自带的动画切换效果

FragmentTransaction fragmentTransaction = mFragmentManager
                .beginTransaction();

fragmentTransaction.setTransition(int transit);

// 通过setTransition(int transit)进行设置
// transit参数说明
// 1. FragmentTransaction.TRANSIT_NONE:无动画
// 2. FragmentTransaction.TRANSIT_FRAGMENT_OPEN:标准的打开动画效果
// 3. FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:标准的关闭动画效果

// 标准动画设置好后,在Fragment添加和移除的时候都会有。

自定义动画效果

// 采用`FragmentTransavtion`的 `setCustomAnimations()`进行设置

FragmentTransaction fragmentTransaction = mFragmentManager
                .beginTransaction();

fragmentTransaction.setCustomAnimations(
                R.anim.in_from_right,
                R.anim.out_to_left);

// 此处的自定义动画效果同Activity,此处不再过多描述

4.2.3 视图组(ViewGroup)中子元素的出场效果

  • 视图组(ViewGroup)中子元素可以具备出场时的补间动画效果
  • 常用需求场景:为 ListView 或 RecyclerView的 item 设置出场动画

使用步骤:

步骤1:设置子元素的出场动画
res/anim/view_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<!--此处采用了组合动画-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000">

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

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

步骤2:设置 视图组(ViewGroup)的动画文件
res/ anim /anim_layout.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="normal"
    android:animation="@anim/view_animation">

    <!--
        android:delay="0.5"  子元素开始动画的时间延迟
        如子元素入场动画的时间总长设置为300ms,那么 delay = "0.5" 表示每个子元素都会延迟150ms才会播放动画效果,
        第一个子元素延迟150ms播放入场效果;第二个延迟300ms,以此类推

        android:animationOrder="normal"  表示子元素动画的顺序
        可设置属性为:
        1、normal :顺序显示,即排在前面的子元素先播放入场动画
        2、reverse:倒序显示,即排在后面的子元素先播放入场动画
        3、random:随机播放入场动画

        android:animation="@anim/view_animation"  设置入场的具体动画效果 -->

</layoutAnimation>

步骤3:为视图组(ViewGroup)指定andorid:layoutAnimation属性
指定的方式有两种: XML / Java代码设置
方式1:在 XML 中指定

<android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?attr/actionBarSize"
        // 指定layoutAnimation属性用以指定子元素的入场动画
        android:layoutAnimation="@anim/anim_layout"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

方式2:在Java代码中指定

这样就不用额外设置res/ anim /anim_layout.xml该xml文件了

ListView lv = (ListView) findViewById(R.id.listView1);

// 加载子元素的出场动画
Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_item);

// 设置LayoutAnimation的属性
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);

// 为ListView设置LayoutAnimation的属性
lv.setLayoutAnimation(controller);

上述二者的效果是一样的。
效果图
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_24382363/article/details/80324767
今日推荐