从本节开始来探究Android中的动画,毕竟在APP中添加上动画,会让的应用变得很炫,比如最简单的关开Activity,当然自定义控件动画肯定必不可少啦~而Android中的动画分为三大类,逐帧动画(Frame)以及补间动画(Tween),还有Android 3.0以后引入的属性动画(Property),而 带来的是第一种动画——逐帧动画的个基本使用~


1.帧动画概念以及用法

帧动画非常容易理解,其实就是简单的由N张静态图片收集起来,然后通过控制依次显示这些图片,因为人眼"视觉残留"的原因,会让造成动画的"错觉",跟放电影的原理一样!

而Android中实现帧动画, 会用到前面讲解到的个DrawableAnimationDrawable先编写好Drawable,然后代码中调用start()以及stop()开始或停止播放动画~

当然也可以在Java代码中创建逐帧动画,创建AnimationDrawable对象,然后调用addFrame(Drawable frame,int duration)向动画中添加帧,接着调用start()和stop()而已~

下面来写两个例子体会下帧动画的效果以及熟悉下用法


2.使用示例

示例一最简单的例子

运行效果图

代码实现

首先编写的动画文件, 先在res下创建个anim目录,接着开始撸的动画文件miao_gif.xml这里的android:oneshot是设置动画是否只是播放一次,true只播放一次,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="@mipmap/img_miao1"
        android:duration="80" />
    <item
        android:drawable="@mipmap/img_miao2"
        android:duration="80" />
    <item
        android:drawable="@mipmap/img_miao3"
        android:duration="80" />
    <!--限于篇幅,省略其他item,自己补上-->
    ...
</animation-list>

动画文件有了,接着到的布局文件activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始" />
    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="停止" />
    <ImageView
        android:id="@+id/img_show"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_gravity="center"
        android:background="@anim/miao_gif" />
    
</LinearLayout>

最后是的MainActivity.java,这里在这里控制动画的开始以及暂停

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_start;
    private Button btn_stop;
    private ImageView img_show;
    private AnimationDrawable anim;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
        anim = (AnimationDrawable) img_show.getBackground();
    }
    private void bindViews() {
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_stop = (Button) findViewById(R.id.btn_stop);
        img_show = (ImageView) findViewById(R.id.img_show);
        btn_start.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
    }
    
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start:
                anim.start();
                break;
            case R.id.btn_stop:
                anim.stop();
                break;
        }
    }
}

非常的简单哈~


示例二在指定地方播放帧动画

运行效果图

代码实现

依旧是先上的动画文件:anim_zhuan.xml

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item
        android:drawable="@mipmap/img_zhuan1"
        android:duration="80" />
    <item
        android:drawable="@mipmap/img_zhuan2"
        android:duration="80" />
    <item
        android:drawable="@mipmap/img_zhuan3"
        android:duration="80" />
     <!--限于篇幅,省略其他item,自己补上-->
    ...
</animation-list> 

接着来写个自定义的ImageViewFrameView.java,这里通过反射获得当前播放的帧,然后是否为最后一帧,是的话隐藏控件!

/**
 * Created by Jay on 2015/11/15 0015.
 */
public class FrameView extends ImageView {
    private AnimationDrawable anim;
    public FrameView(Context context) {
        super(context);
    }
    public FrameView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public FrameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public void setAnim(AnimationDrawable anim){
        this.anim = anim;
    }
    public void setLocation(int top,int left){
        this.setFrame(left,top,left + 200,top + 200);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        try{
            //反射调用AnimationDrawable里的mCurFrame值
            Field field = AnimationDrawable.class
                    .getDeclaredField("mCurFrame");
            field.setAccessible(true);
            int curFrame = field.getInt(anim);// 获取anim动画的当前帧
            if (curFrame == anim.getNumberOfFrames() - 1)// 若已经到了最后一帧
            {
                //让该View隐藏
                setVisibility(View.INVISIBLE);
            }
        }catch (Exception e){e.printStackTrace();}
        super.onDraw(canvas);
    }
}

最后是的MainActivity.java,创建个FrameLayout,添加View,对触摸事件中按下的事件做处理,显示控件以及开启动画~

public class MainActivity extends AppCompatActivity {
    private FrameView fView;
    private AnimationDrawable anim = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout fly = new FrameLayout(this);
        setContentView(fly);
        fView = new FrameView(this);
        fView.setBackgroundResource(R.anim.anim_zhuan);
        fView.setVisibility(View.INVISIBLE);
        anim = (AnimationDrawable) fView.getBackground();
        fView.setAnim(anim);
        fly.addView(fView);
        fly.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //设置按下时才产生动画效果
                if(event.getAction() == MotionEvent.ACTION_DOWN){
                    anim.stop();
                    float x = event.getX();
                    float y = event.getY();
                    fView.setLocation((int) y - 40,(int)x-20);  //View显示的位置
                    fView.setVisibility(View.VISIBLE);
                    anim.start();    //开启动画
                }
                return false;
            }
        });
    }
}

同样很简单哈~


3.本节示例代码和Gif帧提取工具下载

AnimationDemo1.zip

AnimationDemo2.zip

Gif帧提取工具


本节小结

介绍了一下Android三种动画中最简单的帧动画,实际开发用的并不多不过学多点东西,以后也多个思路嘛~ 本节就到这里,