Android动画的应用---三种动画简析

    Android中提供了三种动画,分别是帧动画(Frame Animation),补间动画(Tweened Animation)和属性动画(Property Animation)。下面分别介绍下这三种动画的使用。

一、帧动画(Frame Animation)

    帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,

从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。使用步骤:

    1、在drawable文件夹中新建xml文件
    2、xml文件中的根节点是<animation-list>

    3、例子:

    onshot = true :只播放一次。若为false,则动画会循环播放。

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>

    设置动画:

AnimationDrawable rocketAnimation;

public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
  rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
  rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
}

public boolean onTouchEvent(MotionEvent event) { //触碰屏幕让动画启动
  if (event.getAction() == MotionEvent.ACTION_DOWN) {
    rocketAnimation.start();
    return true;
  }
  return super.onTouchEvent(event);
}
     注意事项:不能再Activity oncreate()中直接让动画start,因为View并未绘制加载完。可以在onWindowFocusChanged方法中调用。


二、补间动画(Tweened Animation)

    补间动画可以分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。

补间动画的实现,一般会采用xml 文件的形式;代码会更容易书写和阅读,同时也更容易复用。

1、使用XML文件形式实现补间动画

扫描二维码关注公众号,回复: 1912250 查看本文章

    1)、在res目录下新建anim文件夹。
    2)、新建xml文件,该文件只能有一个根结点,可以是<set>,<alpha>,<scale>,<translate>,<rotate>,而其中,<set>结点可以包含子节点,即可以包含<set>,<alpha>,<scale>,<translate>,<rotate>,以此类推。

例子:
在xml文件中定义动画

<set android:shareInterpolator="false"> //指定动画效果不共享一个Interpolator
    <scale
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:fromXScale="1.0" //对x轴和y轴进行缩放
        android:toXScale="1.4"
        android:fromYScale="1.0"
        android:toYScale="0.6"
        android:pivotX="50%"  //缩放中心
        android:pivotY="50%"
        android:fillAfter="false" //动画结束后是否停留在最后一帧
        android:duration="700" />
    <set android:interpolator="@android:anim/decelerate_interpolator">
        <scale
           android:fromXScale="1.4"
           android:toXScale="0.0"
           android:fromYScale="0.6"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700" //延时700毫秒启动动画
           android:duration="400"
           android:fillBefore="false" />
        <rotate
           android:fromDegrees="0"
           android:toDegrees="-45"
           android:toYScale="0.0"
           android:pivotX="50%"
           android:pivotY="50%"
           android:startOffset="700"
           android:duration="400" />
    </set>
</set>
调用方式:
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(animation );

2、代码实现补间动画

 // 1&2: 确定起始状态,结束状态  
  TranslateAnimation tAnim = new TranslateAnimation(0, 400, 0, 0);//横向位移400个单位  
  RotateAnimation rAnima = new RotateAnimation(0, 70);//顺时针旋转70度  
  ScaleAnimation sAnima = new ScaleAnimation(0, 5, 0, 5);//横向放大5倍,纵向放大5倍  
  AlphaAnimation aAnima = new AlphaAnimation(1.0f, 0.0f);//从全不透明变为全透明  
  // 3: 确定持续时间  
  tAnim.setDuration(2000);  
  rAnima.setDuration(2000);  
  sAnima.setDuration(2000);  
  aAnima.setDuration(2000);  

  // 4: 确定Interpolator插值器(斜率概念)决定动画变化的一种走势,下面是先加速后减速插值器
  tAnim.setInterpolator(new AccelerateDecelerateInterpolator());  

  // 启动动画  
  textView1.startAnimation(tAnim);  
  textView2.startAnimation(rAnima);  
  textView3.startAnimation(sAnima);  
  textView4.startAnimation(aAnima);     

3、考虑对一组控件进行补间动画---layoutAnimation

    由于layoutAnimation是对于某一组控件的操作,就需要一个基本的动画来定义单个控件的动画。另外还可以定义动画的显示顺序和延迟。可以通过xml文件或者代码来实现该功能。

xml文件实现

1)、在anim文件加下创建layoutAnimation对应的xml文件:layout_animation.xml

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

其中:

  • android:delay表示动画播放的延时,既可以是百分比,也可以是float小数。比如子元素入场动画的时间周期为300ms,那么0.5表示每个子元素都要延迟150ms才能播放入场动画。总体来说第一个元素延迟150ms开始播放入场动画,第二个元素延时300ms开始播放入场动画,以此类推。
  • android:animationOrder表示动画的播放顺序,有三个取值normal(顺序)、reverse(反序)、random(随机)。
  • android:animation指向了子控件所要播放的动画。

2)、定义动画list_item_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:shareInterpolator="true">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
    <translate
        android:fromXDelta="150"
        android:toXDelta="0" />
    <rotate
        android:fromDegrees="180"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="0" />
</set>
3)、为GroupView指定android:layoutAnimation属性
 
<ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layoutAnimation="@anim/anim_layout" />

代码实现:

    需要使用LayoutAnimationController类来实现该功能

ListView listView = (listView)layout.findViewById(R.id.list);
Animation animation = AniamtionUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOder(LayoutANiamtionController.ORDER_NORMAL);  //顺序
listView.setLayoutAnimation(controller);


三、属性动画(Property Animation)

    在Android3.0之后增加了属性动画,属性动画功能很强大,不仅限于补间动画的四种动画,也可以自定义属性动画而且动画也可以作用于非View对象。对于属性动画可以设置动画持续时间,时间插值器,动画的执行次数,动画集合,延时动画刷新等。

    下面看下API文档中提供的图片:


    从图片中可以看出在ValueAnimator中设置了一系列参数后启动动画,可以设置动画更新监听(ValueAnimator.AnimatorUpdateListener),来获取动画过程中对应某一时刻是的属性值(getAnimatedValue)。

下面介绍重点对象:

    ValueAnimator:实时记录动画,记录动画的时间,位置等信息(值变化属性动画),可以查看相关API方法。

    TimeInterpolator:时间插值器(斜率的概念),例如AccelerateInterpolator加速插值器。

    TypeEvaluator:估值器,当我们ValueAnimator.ofObject()函数来做动画效果的时候就会用到估值器了,估值器说白了就是用来确定在动画过程中每时每刻动画的具体值得换句话说就是确定ValueAnimator.getAnimatedValue()返回的具体对象类型。

    ObjectAnimator:是ValueAnimator的子类,作用于任何Object对象。


1、ValueAnimator的使用

    ValueAnimator常用API有ofInt(), ofFloat()和 ofObject()。通过制定一组int类型,float类型或者其他Object类型的值来设置动画效果,使用ValueAnimator创建属性动画,ValueAnimator实现对值进行动画过渡。

1)例:ofFloat方法,将一个值从0平滑过渡到1,时长300毫秒,就可以这样写:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
    animation.setDuration(300);
    animation.start();

    只是值的变化,显然是看不到视觉效果,可以通过打印值的变化来看具体的值,也可以在onAimationUpdate方法中更新一些UI相关操作,比如在自定义view中调用invalidate方法。

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
    anim.setDuration(300);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            float currentValue = (float) animation.getAnimatedValue();  
            Log.d("TAG", "cuurent value is " + currentValue);  
        }  
    });  
    anim.start(); 
    比如说将一个值在5秒内从0过渡到5,再过渡到3,再过渡到10,就可以这样写:
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);  
anim.setDuration(5000);  
anim.start(); 

2)例:ofObject方法实例,需要指定自定义的TypeEvaluator,以及对应的属性值组,下面会在自定义属性中介绍自定义TypeEvaluator。

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

    ValueAnimator是设置一些属性值的动画,可以通过设置监听方法ValueAnimator.AnimatorUpdateListener()监听属性值得变化来执行某一操作。

2、ObjectAnimator的使用

    ObjectAnimator是ValueAnimator的子类,作用于任何Object对象,使用方法和ValueAnimator差不多。由于ObjectAnimator在动画期间自动更新属性,所以得有set方法更新属性值。动画得获取属性的初始值和结束值,所以在动画的对象属性必须具有用于获取动画起始值的get方法。

    注意事项:对应的属性在对象(下面例子是textView)中必须有对应的get和set方法,如alpha属性得有对应的getAlpha()和setAlpha()方法。

1)ofFloat方法

 //alpha      
 ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f); 
 animator.setDuration(5000);  
 animator.start(); 

//旋转
 ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
 animator.setDuration(5000);  
 animator.start(); 

//平移
float curTranslationX = textview.getTranslationX();  
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);  
animator.setDuration(5000);  
animator.start();

    其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此alpha属性所对应的get和set方法应该就是:

public void setAlpha(float value);  
public float getAlpha(); 

2)、组合动画AnimatorSet的使用
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();
动画顺序是平移进入之后,让旋转和淡入淡出动画同时进行。


3、通过xml方式实现属性动画ValueAnimator和ObjectAnimator

  •     首先要在res目录下面新建一个animator文件夹。
  •     XML文件中我们一共可以使用如下三种标签:
        <animator>  对应代码中的ValueAnimator
        <objectAnimator>  对应代码中的ObjectAnimator
        <set>  对应代码中的AnimatorSet

 示例

<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="sequentially" >  //组合动画执行顺序,默认是together,这里是按顺序执行

    <objectAnimator  
        android:duration="2000"  
        android:propertyName="translationX"  
        android:valueFrom="-500"  
        android:valueTo="0"  
        android:valueType="floatType" >  //指定属性值类型(四种类型:colorType,floatType,intType,pathType)pathType用于矢量图动画
    </objectAnimator>  


    <set android:ordering="together" >  
        <objectAnimator  
            android:duration="3000"  
            android:propertyName="rotation"  
            android:valueFrom="0"  
            android:valueTo="360"  
            android:valueType="floatType" >  
        </objectAnimator>  


        <set android:ordering="sequentially" >  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="1"  
                android:valueTo="0"  
                android:valueType="floatType" >  
            </objectAnimator>  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="0"  
                android:valueTo="1"  
                android:valueType="floatType" >  
            </objectAnimator>  
        </set>  
    </set>  
</set>  

    代码调用

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();

    以上是属性动画使用的简单介绍,下面再来总结下属性动画中用到监听器。

4、设置属性动画监听器

1)、AnimatorListener需要实现这四个接口

anim.addListener(new AnimatorListener() {  
    @Override  
    public void onAnimationStart(Animator animation) {  
    }  


    @Override  
    public void onAnimationRepeat(Animator animation) {  
    }  


    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  


    @Override  
    public void onAnimationCancel(Animator animation) {  
    }  
});  

2)、AnimatorListenerAdapter监听适配器,可以根据自己的需要实现某个监听方法。

anim.addListener(new AnimatorListenerAdapter() {  
    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  
});  

3)、ValueAnimator.AnimatorUpdateListener,当使用ValueAnimator动画时才能实现该接口
 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {


            }
        });


5、属性动画中的LayoutTransition---针对ViewGroup布局变化的动画

    属性动画系统提供了对ViewGroup对象进行动画变化的功能,可以使用LayoutTransition类对ViewGroup中的布局更改进行动画处理。 动画体现在如下情况:当向ViewGroup中添加或删除view,或者将view设置为visible,invisible或者gone,出现了消失或显示以及其他views发生了位置变化的情况。相关API:

mLayoutTransition.setAnimator(int transitionType, Animator animator)

transitionType值:

  • APPEARING - 当view item显示时(设置为visible或者add)的动画
  • CHANGE_APPEARING - 由于新的item显示时,若其他view item发生的位置变化的动画
  • DISAPPEARING - 当view item消失时(invisible,gone或者remove)的动画
  • CHANGE_DISAPPEARING -由于view item的消失,若其他view item发生位置变化的动画
animator:属性动画,可以通过xml定义也可以直接new出属性动画对象。


使用实例:下面实例实现的效果是当设置LinearLayout中的一个子view为visible或者addview的动画效果。

LinearLayout linearLayout = findViewById(R.id.ll_main);
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.object_animator);
LayoutTransition layoutTransition = new LayoutTransition();
layoutTransition.setAnimator(LayoutTransition.APPEARING, animator);
linearLayout.setLayoutTransition(layoutTransition);

在animator文件夹下创建object_animator.xml文件

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">
    <objectAnimator
        android:duration="2000"
        android:propertyName="scaleX"
        android:valueFrom="0f"
        android:valueTo="1f"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="2000"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="360"
        android:valueType="floatType" />

</set>

6、属性动画--StateListAnimator

    StateListAnimator对Animator进行了包装,是用来设置控件状态发生变化时的动画。指定的视图状态(例如“按下”或“聚焦”)发生更改就调用该动画。

示例:实现的效果是当手指按压到Button时,Button大小放大到150%,手指离开时恢复原大小

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>
<Button
        android:id="@+id/login_btn"
        android:layout_width="@dimen/login_edit_width"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:stateListAnimator="@xml/animate_scale"
        android:background="@drawable/login_btn_rectangle"
        android:text="@string/login" />

    以上是用xml的形式实现调用该动画,也可以通过代码的形式来加载这个动画。需要使用AnimatorInflater.loadStateListAnimator()方法,并使用View.setStateListAnimator()方法将动画器分配给视图。

StateListAnimator animator = AnimatorInflater.loadStateListAnimator(this, R.xml.animate_scale);
Button button = findViewById(R.id.login_btn);
button.setStateListAnimator(animator);

7、属性动画--ViewPropertyAnimator

    ViewPropertyAnimator是在3.1系统当中附增的一个新的功能,新增该功能是为了让针对view的属性动画使用起来更方便。先来回顾一下之前的用法吧,比如我们想要让一个TextView从常规状态变成透明状态,就可以这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);  
animator.start();  
     如何使用ViewPropertyAnimator来实现同样的效果,ViewPropertyAnimator提供了更加易懂、更加面向对象的API,如下所示:
textview.animate().alpha(0f);  
     如我们想要让textview运动到500,500这个坐标点上, 就可以这样写:
textview.animate().x(500).y(500);  
    ViewPropertyAnimator默认是在定义完属性动画后会自定执行start()方法,也可以显示的执行start方法。下面看下相关API方法,其中By结尾的方法表示相对于当前。可以看出ViewPropertyAnimator用法是很简单的。
 

三、过渡动画AnimatedStateListDrawable

    Android 5.0中的一些系统小部件默认使用这些动画。在关键帧之间添加一些过渡元素,实现动画效果。

例:

res/drawable/transition.xml

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

    <!-- provide a different drawable for each state-->
    <item
        android:id="@+id/pressed"
        android:drawable="@drawable/login_btn_rectangle"
        android:state_pressed="true" />
    <item
        android:id="@+id/focused"
        android:drawable="@drawable/login_btn_rectangle1"
        android:state_focused="true" />
    <item
        android:id="@+id/normal"
        android:drawable="@drawable/login_btn_rectangle2" />

    <!-- specify a transition -->
    <transition
        android:fromId="@+id/normal"
        android:toId="@+id/pressed">
        <animation-list>
            <item
                android:drawable="@drawable/login_btn_rectangle3"
                android:duration="100" />
            <item
                android:drawable="@drawable/login_btn_rectangle1"
                android:duration="100" />
        </animation-list>
    </transition>
</animated-selector>
<Button
        android:id="@+id/login_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/transition"
        android:text="@string/login" />
    以上是对Android动画的简述,希望有所帮助~。

猜你喜欢

转载自blog.csdn.net/white_wt/article/details/80489917