Android当中的动画2—Tween动画


    1、前言:

            在前一篇博客当中楼主介绍了一下关于DrawableAnimation的使用,今天来介绍一下关于Android当中的另外一种动画的实现机制,那就是Tween Animation的实现(补间动画)也有人称呼它为View动画,这种动画框架在Android3.0之前可为是Android中的一家独大,同时也让我们开发人员精疲力尽,为什么这么说呢?因为View动画,他操作的是View的改变,而View的一些具体的属性是没有改变的,最常见的就是我们给他设置的OnClickListener,view移动了,事件却不跟着他进行移动,Google当然也不会容忍这种事发生,所以就在Android3.0以后的 版本当中推出了属性动画来解决我们开发人员所面临的尴尬的问题。我们现在学习它也要掌握它的实现思想。好了,我们来看一看,它的实现吧

    2、正文:
        
        <1>、都有哪些动画?
                其实现在看来我们的Tween Animation确实有一定的局限性,因为他只提供了,透明度,旋转,缩放,位移这几种常见的动画,我们也可以这么理解,就是如果我们掌握了透明度,旋转,缩放,平移,外加它们这些动画是怎么实现的,自己去实现一个自己的动画,那么恭喜你,你可以过关,过关以后,去看楼主的下一篇博客,属性动画。

        <2>、Tween Animation的实现原理。
                刚刚在前面说过Tween Animation定义了几种常见的动画,其实它的实现,就是控制View,在每次绘制视图的时候,去在View的ViewGroup中drawChild方法中获取该View的Animation的Transformation值,canvas.concat(transfoemToApply.getMatrix()),通过矩阵去实现动画的帧,如果该动画没有完成,则通过invalidate()方法进行不断地重绘,从而达到整个动画的绘制

            补充:首先我们应该明白在我们每一个View当中都有一个Animation对象,而这个对象当中有一个Transformation对象,而这个对象里面维护了一个可以根据时间因子改变的Matrix,,然后我们通过canvas.concat(transfoemToApply.getMatrix())获取我们的矩阵,从而实现我们的动画,这一块的内容我也会在后续博客当中跟大家说到。

        
        <3>、API,语法:

                我们的Tween Animation的实现,主要分成了两部分,我们可以通过代码去控制我们的动画,我们也可以通过XML定义我们的动画,定义好了以后我们只需要在代码当中加载一下,便可以使用了,


        在此说一下我自己的想法,我们如果想要一个动画效果,我们肯定需要很多的属性去约束他,而我们可以把属性放在XML当中,让系统自己去加载,我们也可以在代码里面 直接的通过参数的类型传给我们的动画,从而得到一个动画的对象

            <1>、通过XML去定义动画,如果我们要去定义一个XML的动画,我们需要在/res/anim/目录下创建相应的XML文件,

Alpha:淡入淡出动画效果

<span style="font-size:18px;"><alpha   
	android:fromAlpha="1.0"    
	android:toAlpha="0.0"    
        android:duration="500"  />   
			     
<!--    
	fromAlpha:开始时透明度,透明度在0和1之间取值,类型是float类型   
	toAlpha: 结束时透明度 
	duration:动画持续时间 
-->  </span>
 

rotate:旋转效果

<span style="font-size:18px;"><rotate                                        
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"   
        android:fromDegrees="300"   
        android:toDegrees="-360"   
        android:pivotX="10%"   
        android:pivotY="100%"   
        android:duration="10000" />      
<!--    
      fromDegrees   动画开始时的角度
      toDegrees     动画结束时物件的旋转角度,正代表顺时针     
      pivotX    属性为动画相对于物件的X坐标的开始位置  
      pivotY    属性为动画相对于物件的Y坐标的开始位置    
-->  
</span>

          

   scale:缩放效果:

<scale     
	android:interpolator= "@android:anim/decelerate_interpolator"         
	android:fromXScale="0.0"     
	android:toXScale="1.5"     
	android:fromYScale="0.0"     
	android:toYScale="1.5"     
	android:pivotX="50%"     
	android:pivotY="50%"     
	android:startOffset="0"     
	android:duration="10000"    
	android:repeatCount="1"     
	android:repeatMode="reverse"  />     
  
<!--    
	fromXDelta,fromYDelta       起始时X,Y座标,屏幕右下角的座标是X:320,Y:480   
	toXDelta, toYDelta      动画结束时X,Y的座标 
--> 
<!--     
	fromXScale,fromYScale,         动画开始前X,Y的缩放,0.0为不显示,1.0为正常大小  
	toXScale,toYScale,		动画最终缩放的倍数, 1.0为正常大小,大于1.0放大  
	pivotX,  pivotY		动画起始位置,相对于屏幕的百分比,两个都为50%表示动画从屏幕中间开始   
	startOffset,			动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间,单位毫秒 
	duration,			一次动画效果消耗的时间,单位毫秒,值越小动画速度越快 
	repeatCount,			动画重复的计数,动画将会执行该值+1次   
        repeatMode,			动画重复的模式,reverse为反向,当第偶次执行时,动画方向会相反。restart为重新执行,方向不变 
--> 

translate.xml 移动效果:

<set xmlns:android="http://schemas.android.com/apk/res/android">  
    <translate   
        android:fromXDelta="320"   
        android:toXDelta="0"   
        android:fromYDelta="480"   
        android:toYDelta="0"   
        android:duration="10000" />   
</set>   

<!--    
    fromXDelta,fromYDelta   起始时X,Y座标,屏幕右下角的座标是X:320,Y:480   
    toXDelta, toYDelta     动画结束时X,Y的座标 
-->   

下面单独说说关于interpolator
    指定动画插入器,所谓的插入器,说白了就是用来控制动画速度的一个控制器而在XML当中可以使用的是三种,分别是
        accelerate_decelerate_interpolator    先加速-后减速插入器
        accelerate_interpolator,        加速插入器    
        decelerate_interpolator。        减速插入器

当我们定义完成以后呢,我们就可以在Java代码当中使用

 Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXXX);
 view.startAnimation(animation);

以上就是我们使用XML来定义动画的API。下面我们来看看如何使用代码来实现我们的动画,如果我们要去使用代码来实现动画,首先我还是要在这里给大家介绍代码API

           在这里我们首先来看动画的抽象类,Animation,这个类是Tween Animation动画具体实现类的基类,提供了动画启动,停止,重复,持续时间等方法

                   Animation 有如下常用方法:

                      setDuration(long time)    设置动画持续时间,单位为毫秒。

                      startNow(); 启动动画的主要方法,使用之前必须先使用setAnimation()为某一个View对象设置动画,另外用户可以是用View组件的startAnimation();来启动动画。

                      start();和上述方法功能一直,区别在与该方法可以用于getTransfoemation();方法被调用时启动动画

                      cancel();用户取消动画,

                      setRepeatCount(int repeatCount);设置动画重复次数,设置为n 执行n+1次动画,为-1,一直

                      setFillEnables(boolean fillEnabled);根据boolean值来实现是否开启填充效果,

                      setRepeatMode(int repeatMode):RESTART:重新从头开始,REVERSE:表示反方向执行

                       setSatartOffset(long startOffset):动画延迟startOffset毫秒开始执行。


                    AlphaAnimation:透明度变换动画:

                  new AlphaAnimation(float fromAlpha, float toAlpha);构建透明度渐变动画,从fromAlpha到toAlpha


                    ScaleAnimation:缩放动画:

                    new ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, folatpivotXValus,int pivotYType, folatpivotYValus);以(<pivotXType模式,pivotXValus的值>,<pivotYType模式,pivotYValus的值>)坐标点为缩放中心,在X方向比例从fromX到toX,在Y方向比例从fromY到toY。


                   TranslateAnimation:平移动画:

                      newTranslateAnimation(float fromXDelta, float toXDelta,float fromYDelta,float toYDelta);坐标点从( fromXDelta, fromYDelta)到(toXDeltatoYDelta


                    RotateAnimation:旋转动画:

                       newRotateAnimation(float fromDegress, float toDegress,int pivotXType, folat pivotXValus, int pivotYType, folatpivotYValus)以(<pivotXType模式,pivotXValus的值>,<pivotYType模式,pivotYValus的值>)坐标点为旋转中心,从fromDegress度旋转到toDegress


关于动画的插值器,(Interpolators)的使用。

              AccelerateDecelerateInterpolators:慢慢开始和结束,在中间加速。

              AccelerateInterpolators:慢慢开始,然后加快速度。

              AnticipateInterpolator:开始向后,然后向前

              AnticipateOvershootInterpolator:开始向后,然后向前,超过目标值,然后返回目标值

              BounceInterpolator:动画在结束的时候弹起

              CycleInterpolator:动画循环特定的次数,速率变化方式为正玄曲线

              DecelerateInterpolator:开始快,然后慢

              LinearInterpolator:以恒定的速率变化

              OvershootInterpolator:向前冲一定值后再回到原来的位置


TimeInterpolator:这一个比较特殊,它的存在就是为我们自定义而生的,在下一节楼主的博客中,为大家详细讲解


        以上就是动画的所有API,但是我们的问题来了,如果我想对一个View同时去执行多个动画的时候我们应该怎么办呢。这个时候我们就又要介绍另外的一个API了,那就是AniamtionSet,其实大家可以把它想象成为是一个动画的集合,我们把我们所拿到的多个动画放入其中,然后让我们的View对象去开启他就OK了,好了,下面我们直接开始一个Animation的小Demo,让大家可以更好地去理解我们的的Tween Animation。


我们通过几个Button去控制我们的动画,然后用一个ImageView作为这个动画的载体,就这么简单。




大家会觉得为什么在缩放上面的变换不是很平滑呢,那是楼主在上面加入了插值器的效果,插值器效果很多,在这里楼主就不一一列举了,下面给大家看代码,/res/layout/activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ImageView
        android:id="@+id/image"
        android:padding="20dip"
        android:layout_width="match_parent"
        android:layout_height="350dip"
        android:src="@mipmap/empty_logo_black"
        />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        >

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="透明度"
            android:onClick="alpha"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="缩放"
            android:onClick="scale"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:onClick="rotate"
            android:text="旋转"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="平移"
            android:onClick="translate"
            android:textColor="#fff"/>
        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="全部"
            android:onClick="all"
            android:textColor="#fff"/>


    </LinearLayout>


</RelativeLayout>

Java代码如下所示,MainActivity.Java


package com.suansuan.tweenanimation;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    private ImageView mImage;

    private long duration = 1000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImage = (ImageView) findViewById(R.id.image);
    }

    /** 淡入淡出动画 */
    public void alpha(View view){
        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        alphaAnimation.setDuration(duration);

        //保持最后的状态,
        alphaAnimation.setFillAfter(true);
        mImage.startAnimation(alphaAnimation);
    }

    /** 缩放动画 */
    public void scale(View view){
        ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0f, 1f, 0f,ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(duration);
        scaleAnimation.setInterpolator(new AnticipateOvershootInterpolator());
        //保持最后的状态,
        scaleAnimation.setFillAfter(true);
        mImage.startAnimation(scaleAnimation);
    }

    /** 旋转动画 */
    public void rotate(View view){

        RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);

        rotateAnimation.setDuration(duration);

        //保持最后的状态,
        rotateAnimation.setFillAfter(true);
        mImage.startAnimation(rotateAnimation);
    }

    /** 平移动画 */
    public void translate(View view){
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 500);
        translateAnimation.setDuration(duration);

        //保持最后的状态,
        translateAnimation.setFillAfter(true);
        mImage.startAnimation(translateAnimation);
    }

    /** 使用AnimationSet全部执行 */
    public void all(View view){
        AnimationSet animationSet = new AnimationSet(false);

        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        animationSet.addAnimation(alphaAnimation);
        ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0f, 1f, 0f,ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        animationSet.addAnimation(scaleAnimation);
        RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        animationSet.addAnimation(rotateAnimation);
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 500);
        animationSet.addAnimation(translateAnimation);
        animationSet.setDuration(6000);

        mImage.startAnimation(animationSet);
    }
}

最后一点,我说说动画的监听吧,

<pre name="code" class="java">  mAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //动画将要开始的时候的监听回调
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //动画结束的时候的监听回调
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                //当动画重复时回调
            }
        });


 

 
好了 以上就是我们Tween Animation的基础知识,其实在我们平时开发当中还有好多,一篇博客根部就写不完,所以在这里说下常用的基础知识。好了,下面我们去做一个练习,我们做一个在我们的ListView下拉的时候,我们下来出来的Item增加动画效果,好了我们先看一下效果,很简单对吧,但是有很多的Bug,没关系,我们学习了属性动画以后会在很大的程度上面去改变,去优化的。 

我们去看看是怎么实现的把,我们这里使用到了一个开源的库,而这个库的作用就是随机生成好看的颜色,

compile 'com.github.lzyzsd.randomcolor:library:1.0.0'
这就是这个库的链接,如果是使用Eclipse的同学,请到Github上面下载,我们先看资源文件/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="5dip"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:dividerHeight="5dip"
        />
</LinearLayout>

很简短,就是一个ListView。


package com.suansuan.textapplication.textanimator;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.ScaleAnimation;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;

import com.github.lzyzsd.randomcolor.RandomColor;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private AnimationSet mAnimation;
    private List<Integer> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    /** 初始化View */
    private void initView() {
        ListView mListView = (ListView) findViewById(R.id.lv);
        initAnimation();
        list = new ArrayList<>();
        mListView.setAdapter(new MyAdapter());
    }

    /** 初始化Animation */
    private void initAnimation() {
        mAnimation = new AnimationSet(true);
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.8f, 1f, 1f, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        mAnimation.addAnimation(scaleAnimation);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1f);
        mAnimation.addAnimation(alphaAnimation);

        mAnimation.setDuration(1000);
        mAnimation.setInterpolator(new AnticipateOvershootInterpolator());
    }

    /** ListView的数据适配器 */
    class MyAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return 20;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            RandomColor randomColor = new RandomColor();
            if(convertView == null){
                convertView = new ImageView(getApplicationContext());
                AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, 400);
                convertView.setLayoutParams(layoutParams);
                convertView.setBackgroundColor(randomColor.randomColor());
            }else{
                convertView.setBackgroundColor(randomColor.randomColor());
            }

            /** 使用List的原因就是在我们的Item第一次出来的时候进行动画展示,以后不用再做动画展示 */
            if (!list.contains(position)) {
                convertView.startAnimation(mAnimation);
                list.add(position);
            }

            return convertView;
        }
    }

}

好了,今天的博客就到这里了,感谢各位观看,我们一起努力,一起快乐的码代码,我是刘酸酸,有错请指出,谢谢



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值