Material Design Animation( View动画)

1.视图动画(View 动画)

自从有了属性动画,View 动画的处境就非常凄凉,但有时我们需要的仅仅就是简易的动画效果,那我们使用 View 动画起来就十分便捷。

View 动画的一个特点就是,他的动画仅仅是动的 View 的绘制地方,View 真正的位置并没有一起动画。

View 一般会用作直接作用页面中的 View 上,实现基本的动画效果:平移、旋转、缩放、透明度、或前几者的交集:

除了这几种用法还有几种特殊的使用场景:

给 PopupWindow 设置显示隐藏的动画效果

Activity 设置页面跳转、退出动画效果

Activity 过场动画效果可以通过很多方式设置,而使用 View 动画实现的方式就是借助设置

overridePendingTransition(int enterAnim, int exitAnim) 方法。跟在 startActivity() 或 finish() 后面,在页面转换时就显示上面方法设置的切换动画效果。

ViewGroup 设置子控件的进场动画效果

就是通过给 ViewGroup 控件设置一条 android:layoutAnimation="@anim/anim_layout" 的属性。而 anim_layout 就是 ViewGroup 中子控件在第一次显示时的进场动画效果。

LayoutAnimation 适用于所有的 ViewGroup ,自然也包含 ListView、RecyclerView 等控件。上面说过 LayoutAnimation 提供的是进场动画效果,所以只在 ViewGroup 第一次加载子 View 时显示一次,所以列表控件的 item 加载动画我们一般不使用它,我们会使用 列表 专门的 Item 加载动画, 比如 recyclerView.setItemAnimator() 等

1. 概述:

视图动画,也叫 Tween (补间)动画可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度)。 譬如,如果你有一个 TextView 对象,您可以移动、旋转、缩放、透明度设置其文本,当然,如果它有一个背景图像,背景图像会随着文本变化。

补间动画通过 XML 或 Android 代码定义,建议使用 XML 文件定义,因为它更具可读性、可重用性。

Animation 属性详解

xml 属性                                   java 方法                                          解释

android:detachWallpaper        setDetachWallpaper(boolean)         是否在壁纸上运行

android:duration                     setDuration(long)                             动画持续时间,毫秒为单位

android:fillAfter                       setFillAfter(boolean)                         控件动画结束时是否保持动画最后的状态

android:fillBefore                    setFillBefore(boolean)                      控件动画结束时是否还原到开始动画前的状态

android:fillEnabled                 setFillEnabled(boolean)                    与android:fillBefore效果相同

android:interpolator               setInterpolator(Interpolator)              设定插值器(指定的动画效果,譬如回弹等)

android:repeatCount             setRepeatCount(int)                          重复次数

android:repeatMode              setRepeatMode(int)                          重复类型有两个值,reverse表示倒序回放,restart表示从头播放

android:startOffset                setStartOffset(long)                          调用start函数之后等待开始运行的时间,单位为毫秒

android:zAdjustment              setZAdjustment(int)                          表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal

也就是说,无论我们补间动画的哪一种都已经具备了这种属性,也都可以设置使用这些属性中的一个或多个。

那接下来我们就看看每种补间动画特有的一些属性说明吧。

2.1 Alpha 属性详解

xml 属性                                 java方法                                                           解释       

android:fromAlpha                AlphaAnimation(float fromAlpha, …)                 动画开始的透明度(0.0到   1.0,     0.0   是全透明,1.0是不透明)

android:toAlpha                    AlphaAnimation(…, float toAlpha)                     动画结束的透明度,同上

2-2 Rotate 属性详解

xml 属性                               java方法                                                                           解释

android:fromDegrees          RotateAnimation(float fromDegrees, …)                           旋转开始角度,正代表顺时针度数,负代表逆时针度数

android:toDegrees              RotateAnimation(…, float toDegrees, …)                         旋转结束角度,正代表顺时针度数,负代表逆时针度数

android:pivotX                     RotateAnimation(…, float pivotX, …)                                 缩放起点X坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)

android:pivotY                     RotateAnimation(…, float pivotY)                                       缩放起点Y坐标,同上规律

2-3 Scale 属性详解

xml 属性                                    java方法                                                       解释

android:fromXScale             ScaleAnimation(float fromX, …)               初始X轴缩放比例,1.0表示无变化

android:toXScale                 ScaleAnimation(…, float toX, …)              结束X轴缩放比例

android:fromYScale             ScaleAnimation(…, float fromY, …)          初始Y轴缩放比例

android:toYScale                 ScaleAnimation(…, float toY, …)              结束Y轴缩放比例

android:pivotX                      ScaleAnimation(…, float pivotX, …)         缩放起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)

android:pivotY                      ScaleAnimation(…, float pivotY)              缩放起点Y轴坐标,同上规律

2-4 Translate 属性详解

xml 属性                                   java方法                                                                                       解释

android:fromXDelta             TranslateAnimation(float fromXDelta, …)                                  起始点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点)

android:fromYDelta             TranslateAnimation(…, float fromYDelta, …)                             起始点Y轴从标,同上规律

android:toXDelta                  TranslateAnimation(…, float toXDelta, …)                               结束点X轴坐标,同上规律

android:toYDelta                  TranslateAnimation(…, float toYDelta)                                    结束点Y轴坐标,同上规律

2-5. AnimationSet 详解

AnimationSet 继承自 Animation,是上面四种的组合容器管理类,没有自己特有的属性,他的属性继承自 Animation,所以特别注意, 当我们对 set 标签使用 Animation 的属性时会对该标签下的所有子控件都产生影响。

3. 视图动画 Interpolator 插值器详解

 java 类                                                         xml id值                                                                                          描述

 AccelerateDecelerateInterpolator        @android:anim/accelerate_decelerate_interpolator                   动画始末速率较慢,中间加速

 AccelerateInterpolator                          @android:anim/accelerate_interpolator                                     动画开始速率较慢,之后慢慢加速

 AnticipateInterpolator                           @android:anim/anticipate_interpolator                                       开始的时候从后向前甩

 AnticipateOvershootInterpolator           @android:anim/anticipate_overshoot_interpolator                      类似上面 AnticipateInterpolator

 BounceInterpolator                               @android:anim/bounce_interpolator                                           动画结束时弹起

 CycleInterpolator                                  @android:anim/cycle_interpolator                                               循环播放速率改变为正弦曲线

 DecelerateInterpolator                         @android:anim/decelerate_interpolator                                        动画开始快然后慢

 LinearInterpolator                                @android:anim/linear_interpolator                                                 动画匀速改变

 OvershootInterpolator                        @android:anim/overshoot_interpolator                                          向前弹出一定值之后回到原来位置

 PathInterpolator                                                                                                                                       新增,定义路径坐标后按照路径坐标来跑。

如上就是系统提供的一些插值器,下面我们来看看怎么使用他们。

3.1插值器使用方法

插值器的使用比较简答,如下:

<set android:interpolator="@android:anim/accelerate_interpolator">
    ...
</set>

3.2 插值器的自定义

有时候你会发现系统提供的插值器不够用,可能就像 View 一样需要自定义。所以接下来我们来看看插值器的自定义, 关于插值器的自定义分为两种实现方式,xml 自定义实现(其实就是对现有的插值器的一些属性修改)或者 java 代码实现方式。如下我们来说说。

先看看 XML 自定义插值器的步骤:

  1. 在 res/anim/ 目录下创建 filename.xml 文件。
  2. 修改你准备自定义的插值器如下:
  3. 在你的补间动画文件中引用该文件即可。
  <?xml version="1.0" encoding="utf-8"?>
   <InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
      android:attribute_name="value"
      />

可以看见上面第二步修改的是现有插值器的一些属性,但是有些插值器却不具备修改属性,具体如下:

<accelerateDecelerateInterpolator>
无可自定义的 attribute。

<accelerateInterpolator>
android:factor 浮点值,加速速率(默认值为1)。

<anticipateInterploator>
android:tension 浮点值,起始点后拉的张力数(默认值为2)。

<anticipateOvershootInterpolator>
android:tension 浮点值,起始点后拉的张力数(默认值为2)。 android:extraTension 浮点值,拉力的倍数(默认值为1.5)。

<bounceInterpolator>
无可自定义的 attribute。

<cycleInterplolator>
android:cycles 整形,循环的个数(默认为1)。

<decelerateInterpolator>
android:factor 浮点值,减速的速率(默认为1)。

<linearInterpolator>
无可自定义的 attribute。

<overshootInterpolator>
android:tension 浮点值,超出终点后的张力(默认为2)。

再来看看 Java 自定义插值器的(Java 自定义插值器其实是 xml 自定义的升级,也就是说如果我们修改 xml 的属性还不能满足需求,那就可以选择通过 Java 来实现)方式。

可以看见上面所有的 Interpolator 都实现了 Interpolator 接口,而 Interpolator 接口又继承自 TimeInterpolator, TimeInterpolator 接口定义了一个 float getInterpolation(float input);方法,这个方法是由系统调用的, 其中的参数 input 代表动画的时间,在 0 和 1 之间,也就是开始和结束之间。

如下就是一个动画始末速率较慢、中间加速的 AccelerateDecelerateInterpolator 插值器:

public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    ......
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    ......
}

到此整个补间动画与补间动画的插值器都分析完毕了。

4. 视图动画使用方法
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator="true">

<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />

</
set>

使用:

ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);

上面就是一个标准的使用我们定义的补间动画的模板。至于补间动画的使用,Animation 还有如下一些比较实用的方法介绍:

 

Animation类的方法                                                             解释

reset()                                                                         重置 Animation 的初始化

cancel()                                                                       取消 Animation 动画

start()                                                                          开始 Animation 动画

setAnimationListener(AnimationListener listener)        给当前 Animation 设置动画监听

hasStarted()                                                                 判断当前 Animation 是否开始

hasEnded()                                                                  判断当前 Animation 是否结束

 

View类的常用动画操作方法                                                 解释

startAnimation(Animation animation)                          对当前 View 开始设置的 Animation 动画

clearAnimation()                                                          取消当 View 在执行的 Animation 动画

 

5. 特别特别注意:
补间动画执行之后并未改变 View 的真实布局属性值。切记这一点,譬如我们在 Activity 中有一个 Button 在屏幕上方, 我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点击屏幕下方动画执行之后的 Button 是没有任何反应的, 而点击原来屏幕上方没有 Button 的地方却响应的是点击Button的事件。

 
6. View 动画几种特殊使用场景

View 动画的一个特点就是,他的动画仅仅是动的 View 的绘制地方,View 真正的位置并没有一起动画。
View 除了会用作直接作用的页面中的view之外,通常还用用在下面一些地方。

使用在 PopupWindow 上
private void initWindow() {
        View view = new View(this);
        view.setBackground(getDrawable(R.drawable.xiaomao));
        popupWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }


然后给按钮的点击事件设置为显示 PopupWindow:

btnRun.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (popupWindow.isShowing()) {
                    popupWindow.dismiss();
                } else {
                    popupWindow.showAsDropDown(btnRun);
                }
            }
        });


加动画

那么现在加上一个动画,首先要定义动画。

进入的动画:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000"
        />
</set>

消失的动画:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="0"
        android:toYDelta="100%"
        android:duration="2000" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0"
        android:duration="2000"
        />
</set>

做成一个 style, 在 res/values/styles.xml 文件里加上:

<style name="pop_anim">
    <item name="android:windowEnterAnimation">@anim/pop_in</item>
    <item name="android:windowExitAnimation">@anim/pop_out</item>
</style>

设置动画
这一步就很简单,就加一行代码

private void initWindow() {
        View view = new View(this);
        view.setBackground(getDrawable(R.drawable.xiaomao));
        popupWindow = new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setAnimationStyle(R.style.pop_anim);
    }

Activity 过场动画

1.通过 overridePendingTransition

这种方法写着简单但是不好用,通过 overridePendingTransition,他的两个参数分别是新 Activity 进入时的动画和旧 Activity 退出时的动画. 如果设置为 0 则没有动画。

这个方法必须跟在 startActivity()finish() 后面才会生效。

还是先定义两个动画:

进入时的动画:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000"
        />
</set>

退出时的动画:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="0"
        android:toYDelta="-100%"
        android:duration="2000" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0"
        android:duration="2000"
        />
</set>

跳转时调用:

startActivity(new Intent(MainActivity.this,SecondActivity.class));
overridePendingTransition(R.anim.activity_in,R.anim.activity_out);


2.通过 style

首先看 res/values/styles.xml。定义了一个叫 ActivityAnimstyle,里面有四个属性,分表代表下面的含义

属性                                                     含义

activityOpenEnterAnimation           打开一个新的 Activity 时,要显示的新的 Activit 执行的动画

activityOpenExitAnimation               打开一个新的 Activity 时,当前的旧的 Activit 执行的动画

activityCloseEnterAnimation           关闭一个 activity 时,要显示的上一个 Activity 执行的动画

activityCloseExitAnimation              关闭一个 activity 时,被关闭的 Activity 执行的动画

这四个动画可以针对需要只设置需要的。

把 ActivityAnim 设置给 App 要用的主题 AppTheme 的 android:windowAnimationStyle 属性

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowAnimationStyle">@style/ActivityAnim</item>
</style>
 
    <style name="ActivityAnim">
        <item name="android:activityOpenEnterAnimation">@anim/activity_in</item>
        <item name="android:activityOpenExitAnimation">@anim/activity_out</item>
        <item name="android:activityCloseEnterAnimation">@anim/activity_close_in</item>
        <item name="android:activityCloseExitAnimation">@anim/activity_close_out</item>
    </style>
</resources>
 

在后再清单文件里引用这个主题:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sunlinlin.animademo">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"></activity>
    </application>
</manifest>

上面的四个动画分别是:

activity_in:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000" />
</set>

activity_out:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="0"
        android:toYDelta="-100%"
        android:duration="2000" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0"
        android:duration="2000" />
</set>

activity_close_in:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="-100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000" />
</set>

activity_close_out:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="0"
        android:toYDelta="100%"
        android:duration="2000" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0"
        android:duration="2000" />
</set>


给 ViewGroup 的子控件加进场动画

LayoutAnimation 是作用于 ViewGroup 的,用来指定 ViewGroup 的子控件出现的动画

先做一个子控件出现的动画, 从之前随便选个 activity_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000" />
</set>

准备好了动画,接下来有两种方法,也是 xml 和 java

通过 XML

然后新建一个动画文件, 这里叫anim_layout.xml, 这里有三个属性:

属性                                                                                                   作用

android:delay                                                            可以取值为数值,百分数,或百分数 p。表示两个子控件执行出场动画的间隔时间,为 0 时,所有控件的动画没有延迟全部开始执行;为 1 时表示等上一个控件动画执行完毕才开始执行下一个;为 0.5 时表示等上一个控件动画执行一半开始执行下一个。可以大于 1。。。当这个值为百分数时,如 50%,表示这个延迟时间是当前动画执行时间的 50%。。。当这个值是百分数 p 的时候,如 50%p, 表示这个延迟时间是父 View 的动画时间的 50%。

android:animationOrder                                            有三个值::normal 表示按正常顺序出现。random 表示乱序出现。reverse 表示反序出现。

android:animation                                                      指定出现时要执行的动画

 

anim_layout.xml 文件代码, 设置上一个动画执行五分之一时开始下一个动画,倒序执行:

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.2"
    android:animationOrder="reverse"
    android:animation="@anim/activity_in">
</layoutAnimation>


然后在 Activity 的布局文件中,将一个 LinearLayout 通过 android:layoutAnimation 加上了这个动画:

<LinearLayout
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/btn_back"
    android:layoutAnimation="@anim/anim_layout"
    android:orientation="vertical">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="哈哈" />
</LinearLayout>

通过 java

这里不需要建新的文件了。觉得比上面的方便许多,效果跟上面是一样的。

ll = (LinearLayout) findViewById(R.id.ll);
Animation animation = AnimationUtils.loadAnimation(this,R.anim.activity_in);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.2f);
controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
ll.setLayoutAnimation(controller);
 


猜你喜欢

转载自www.cnblogs.com/neowu/p/10900895.html