Android Frame Animation 帧动画
Android 中的动画分为三大类 逐帧动画(Frame) 、 补间动画(Tween) 、属性动画 (Property)
帧动画
帧动画 就是简单的由 N 张静态图片收集起来,然后通过控制依次显示这些图片,因为人眼"视觉残留"的原因,会让我们造成动画的"错觉",跟放电影的原理一样
而Android中实现帧动画,一般我们会用到一个 Drawable
AnimationDrawable
先编写好 Drawable
,然后代码中调用 start()
以及 stop()
开始或停止播放动画
当然我们也可以在Java代码中创建逐帧动画,创建 AnimationDrawable
对象,然后调用
addFrame(Drawable frame,int duration)
向动画中添加帧,接着调用 start()
和 stop()
简单范例
-
创建一个 空的 Android 项目
cn.twle.android.FrameAnim
-
下载 /static/i/android/tuzi.zip 并把所有的图片拖到
res/drawable
目录下 -
在
red/drawable
目录下创建动画Drawable
anim_tuzi.xmlandroid: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="@drawable/tuzi_1" android:duration="80" /> <item android:drawable="@drawable/tuzi_2" android:duration="80" /> <item android:drawable="@drawable/tuzi_3" android:duration="80" /> <item android:drawable="@drawable/tuzi_4" android:duration="80" /> <item android:drawable="@drawable/tuzi_5" android:duration="80" /> <item android:drawable="@drawable/tuzi_6" android:duration="80" /> <item android:drawable="@drawable/tuzi_7" android:duration="80" /> <item android:drawable="@drawable/tuzi_8" android:duration="80" /> <item android:drawable="@drawable/tuzi_9" android:duration="80" /> <item android:drawable="@drawable/tuzi_10" android:duration="80" /> <item android:drawable="@drawable/tuzi_11" android:duration="80" /> <item android:drawable="@drawable/tuzi_12" android:duration="80" /> </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="停止" /> <TextView android:id="@+id/img_show" android:layout_width="48dp" android:layout_height="48dp" android:layout_gravity="center" android:background="@drawable/anim_tuzi" /> </LinearLayout>
-
修改 MainActivity.java 控制动画的开始以及暂停
package cn.twle.android.frameanim; import android.graphics.drawable.AnimationDrawable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_start; private Button btn_stop; private TextView 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 = (TextView) 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; } } }
在指定地方播放帧动画
-
创建一个 空的 Android 项目
cn.twle.android.TouchAnim
-
下载 /static/i/android/tuzi.zip 并把所有的图片拖到
res/drawable
目录下 -
在
red/drawable
目录下创建动画Drawable
anim_tuzi.xmlandroid: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="@drawable/tuzi_1" android:duration="80" /> <item android:drawable="@drawable/tuzi_2" android:duration="80" /> <item android:drawable="@drawable/tuzi_3" android:duration="80" /> <item android:drawable="@drawable/tuzi_4" android:duration="80" /> <item android:drawable="@drawable/tuzi_5" android:duration="80" /> <item android:drawable="@drawable/tuzi_6" android:duration="80" /> <item android:drawable="@drawable/tuzi_7" android:duration="80" /> <item android:drawable="@drawable/tuzi_8" android:duration="80" /> <item android:drawable="@drawable/tuzi_9" android:duration="80" /> <item android:drawable="@drawable/tuzi_10" android:duration="80" /> <item android:drawable="@drawable/tuzi_11" android:duration="80" /> <item android:drawable="@drawable/tuzi_12" android:duration="80" /> </animation-list>
-
自定义 ImageView: FrameView.java
通过反射获得当前播放的帧,然后是否为最后一帧,如果是则隐藏控件
package cn.twle.android.touchanim; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import java.lang.reflect.Field; 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); // 获取 anim 动画的当前帧 int curFrame = field.getInt(anim); // 如果已经到了最后一帧 if (curFrame == anim.getNumberOfFrames() - 1) { //让该View隐藏 setVisibility(View.INVISIBLE); } }catch (Exception e){e.printStackTrace();} super.onDraw(canvas); } }
-
修改
MainActivity.java
创建一个
FrameLayout
,添加View
,对触摸事件中按下的事件做处理,显示控件以及开启动画package cn.twle.android.touchanim; import android.graphics.drawable.AnimationDrawable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; 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.drawable.anim_tuzi); 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; } }); } }