在开始实例讲解之前,先引用官方文档中的一段话:
Frame动画是一系列图片按照一定的顺序展示的过程,和放电影的机制很相似,我们称为逐帧动画。Frame动画可以被定义在XML文件中,也可以完全编码实现。
如果被定义在XML文件中,我们可以放置在/res下的anim或drawable目录中(/res/[anim | drawable]/filename.xml),文件名可以作为资源ID在代码中引用;如果由完全由编码实现,我们需要使用到AnimationDrawable对象。
如果是将动画定义在XML文件中的话,语法如下:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot=["true" | "false"] > <item android:drawable="@[package:]drawable/drawable_resource_name" android:duration="integer" /> </animation-list>
- 配置图片资源文件
- 在activity中实现frame动画
实例:
运行效果:
步骤
把图片放到res/drawable目录下
分别取名为:a1.png,a2.png,a3.png,a4.png,a5.png,a6.png。
在res/anim目录下创建一个XML配置文件
我们可以将frame.xml文件放置于drawable或anim目录,官方文档上是放到了drawable中了,大家可以根据喜好来放置,放在这两个目录都是可以运行的。
<?xml version="1.0" encoding="utf-8"?> <!-- 根标签为animation-list 其中oneshot代表着是否只展示一遍,设置为false会不停的循环播放动画 根标签下,通过item标签对动画中的每一个图片进行声明 android:duration 表示展示所用的该图片的时间长度 --> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/a1" android:duration="1000"></item> <item android:drawable="@drawable/a2" android:duration="1000"></item> <item android:drawable="@drawable/a3" android:duration="1000"></item> <item android:drawable="@drawable/a4" android:duration="1000"></item> <item android:drawable="@drawable/a5" android:duration="1000"></item> <item android:drawable="@drawable/a6" android:duration="1000"></item> </animation-list>
- animation-list:动画的总标签,这里面放着帧动画 <item>标签
- oneshot代表着是否只展示一遍
- true 则表示动画只播发一次
- false会不停的循环播放动画
- true 则表示动画只播发一次
- oneshot代表着是否只展示一遍
- item:记录着每一帧的信息,对动画中的每一个图片进行声明
- android:drawable="@drawable/a"表示这一帧用的图片为"a",下面以此类推。
- android:duration="1000" 表示这一帧持续1000毫秒,可以根据这个值来调节动画播放的速度
在res/layout目录下创建layout配置文件activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" /> <Button android:id="@+id/btn_begin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/imageView1" android:layout_marginTop="30dp" android:layout_toRightOf="@+id/btn_codeBegin" android:onClick="click" android:text="开始" /> <Button android:id="@+id/btn_stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/btn_begin" android:layout_marginRight="15dp" android:onClick="click" android:text="停止" /> <RadioGroup android:id="@+id/rg_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/btn_stop" android:orientation="horizontal" > <RadioButton android:id="@+id/rb_one" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="单次播放" /> <RadioButton android:id="@+id/rb_more" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="循环播放" /> </RadioGroup> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/rg_num" android:text="拖动进度条修改透明度(0 - 255)之间" /> <SeekBar android:id="@+id/sb_alpha" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/textView1" /> <Button android:id="@+id/btn_codeBegin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/btn_stop" android:layout_marginRight="15dp" android:layout_toRightOf="@+id/btn_stop" android:text="代码_启动" android:onClick="click" /> </RelativeLayout>
Activity代码
package com.example.lession13_frame; import android.app.Activity; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.Toast; public class SplashActivity extends Activity { private ImageView imageView; private AnimationDrawable animationDrawable; private RadioGroup rgNum; private SeekBar sbalpha; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 帧动画 imageView = (ImageView) findViewById(R.id.imageView1); rgNum = (RadioGroup) this.findViewById(R.id.rg_num); sbalpha = (SeekBar) this.findViewById(R.id.sb_alpha); // 第一种方式实现的动画 /* * animationDrawable = (AnimationDrawable) * getResources().getDrawable(R.anim.framebyframe); * imageView.setBackgroundDrawable(animationDrawable); */ // 第二种方式实现的动画 // 设置背景资源 imageView.setBackgroundResource(R.anim.framebyframe); animationDrawable = (AnimationDrawable) imageView.getBackground(); // animationDrawable.setOneShot(false);是否循环播放 // animationDrawable.stop();停止播放 // animationDrawable.isRunning();//是否播放 // animationDrawable.getNumberOfFrames();//播放帧 // animationDrawable.getFrame(index); 返回制定索引的 Drawable对象 // animationDrawable.getDuration(i);停留的时间 rgNum.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub if (checkedId == R.id.rb_one) { // 设置单次播放 animationDrawable.setOneShot(true); } else if (checkedId == R.id.rb_more) { // 设置循环播放 animationDrawable.setOneShot(false); } // 设置播放后重新启动 animationDrawable.stop(); animationDrawable.start(); } }); // 监听的进度条修改透明度 sbalpha.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub // 设置动画Alpha值 animationDrawable.setAlpha(progress); // 通知imageView 刷新屏幕 imageView.postInvalidate(); } }); } public void click(View v) { int id = v.getId(); switch (id) { case R.id.btn_begin: animationDrawable.start(); break; case R.id.btn_stop: animationDrawable.stop(); break; case R.id.btn_codeBegin: Toast.makeText(getApplicationContext(), "------------------", 0) .show(); // 完全编码实现的动画效果 for (int i = 1; i <= 6; i++) { // 根据资源名称和目录获取R.java中对应的资源ID int picId = getResources().getIdentifier("a" + i, "drawable", getPackageName()); // 根据资源ID获取到Drawable对象 Drawable drawable = getResources().getDrawable(picId); // 将此帧添加到AnimationDrawable中 animationDrawable.addFrame(drawable, 300); } animationDrawable.setOneShot(false); // 设置为loop imageView.setBackgroundDrawable(animationDrawable); // 将动画设置为ImageView背景 animationDrawable.start(); // 开始动画 break; default: break; } } }
AnimationDrawable 就是用来控制这个帧动画,这个类中提供了很多方法。
- animationDrawable.start(); 开始这个动画
- animationDrawable.stop(); 结束这个动画
- animationDrawable.setAlpha(100);设置动画的透明度, 取值范围(0 - 255)
- animationDrawable.setOneShot(true); 设置单次播放
- animationDrawable.setOneShot(false); 设置循环播放
- animationDrawable.isRunning(); 判断动画是否正在播放
- animationDrawable.getNumberOfFrames(); 得到动画的帧数。
拖动进度条设置Alpha值的时候 一定要使用 imageView.postInvalidate(); 方法来通知UI线程重绘屏幕中的imageView 否则会看不到透明的效果 。
纯代码实现:
//完全编码实现的动画效果 for (int i = 1; i <= 6; i++) { //根据资源名称和目录获取R.java中对应的资源ID int picId = getResources().getIdentifier("a" + i, "drawable", getPackageName()); //根据资源ID获取到Drawable对象 Drawable drawable = getResources().getDrawable(picId); //将此帧添加到AnimationDrawable中 animationDrawable.addFrame(drawable, 300); } animationDrawable.setOneShot(false); //设置为loop imageView.setBackgroundDrawable(animationDrawable); //将动画设置为ImageView背景 animationDrawable.start(); //开始动画 break;