Android补间、逐帧动画
程序员文章站
2022-03-25 14:50:05
...
目录
1.逐帧动画
1)AnimationDrawable实现
一帧帧的播放动画过程的静态图片,利用的是人眼视觉暂留的原理,给用户造成“动画”的错觉。
第一步:
在/res/drawable目录下,定义一个逐帧动画的资源文件pic_data.xml
<?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/pic01" android:duration="120"/>
<item android:drawable="@drawable/pic02" android:duration="120"/>
<item android:drawable="@drawable/pic03" android:duration="120"/>
<item android:drawable="@drawable/pic04" android:duration="120"/>
</animation-list>
第二步:xml中定义ImageView显示图片资源
<ImageView
android:id="@+id/anim"
android:src="@drawable/pic_data"//drawable下定义的资源文件名
android:layout_width="200dp"
android:layout_height="200dp"/>
第三步:act使用
iv = (ImageView) findViewById(R.id.anim);
iv.setImageResource(R.drawable.fat_po);
AnimationDrawable anim = (AnimationDrawable) iv.getDrawable();
//开启
anim.start();
//停止
anim.stop();
2)SurfaceView实现
图片少的情况下,可以选择第一种,但是如果图片帧数多,很容易OOM。所以选择不停的在Surfaceview上绘制bitmap,并在绘制玩后回收bitmap
public class MSur extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder surfaceHolder;
private Canvas canvas;
private boolean isDrawing;
private int loadPicPositon = -1;
private List listPic;
private Rect rect = new Rect();
private Thread thread;
public MSur(Context context) {
super(context);
initView();
}
public MSur(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MSur(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public void initView() {
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
listPic = new ArrayList();
for (int i = 0; i < 20; i++) {
if (i % 2 == 0)
listPic.add(R.mipmap.draw_img);
listPic.add(R.mipmap.ic_launcher);
}
this.setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDrawing = true;
thread = new Thread(this);
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
rect.set(0, 0, width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDrawing = false;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while (isDrawing) {
loadPicPositon++;
loadPicPositon = (loadPicPositon == listPic.size()) ? 0 : loadPicPositon;
draw(loadPicPositon);
}
long end = System.currentTimeMillis();
//加上线程睡眠时间,防止太频繁的绘制
if (end - start <= 100) {
try {
Thread.sleep(100 - (end - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void draw(int picPo) {
Bitmap btp = null;
try {
btp = BitmapFactory.decodeResource(getResources(), (Integer) listPic.get(picPo));
//拿到绘图对象
canvas = surfaceHolder.lockCanvas();
if (btp == null || canvas == null) {
return;
}
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(btp, null, rect, null);
//绘制内容
} catch (Exception e) {
Log.e("draw: ", e.toString());
thread.interrupt();
} finally {
//将绘图的内容提交
surfaceHolder.unlockCanvasAndPost(canvas);
btp.recycle();
}
}
public void pouse(){
isDrawing = false;
}
public void stopAnim() {
listPic.clear();
isDrawing = false;
thread.interrupt();
}
}
内存情况也比较稳定:
2.补间动画
1)旋转动画
属性:
fromDegrees 开始旋转的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
toDegrees 结束时旋转到的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
pivotX 缩放起点 X 轴坐标,可以是数值、百分数、百分数 p 三种样式
50、50%、50%p
pivotY 缩放起点 Y 轴坐标,可以是数值、百分数、百分数 p 三种样式
50、50%、50%p
duration 动画持续时间,以毫秒为单位
fillAfter 如果设置为 true,控件动画结束时,将保持动画最后时的状态
fillBefore 如果设置为 true,控件动画结束时,还原到开始动画前的状态
fillEnabled 与 fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
repeatCount 重复次数
repeatMode 重复类型,reverse 表示倒序回放,restart 表示重新放一遍
必须与 repeatCount 一起使用才能看到效果
interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等
xml方式:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-360" />
使用:
ImageView image= (ImageView) findViewById(R.id.image);
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate_anim);
image.startAnimation(rotateAnimation);
java方式:
前两个构造,都是旋转角度,加上设置旋转中心。最后一个构造,可以设置旋转动画的参考系,看如下示例:
//设置旋转参考系为自身中心点
Animation rotateAnimation = new RotateAnimation
(0,360,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(500);
rotateAnimation.setFillAfter(true);
//设置动画插入器
rotateAnimation.setInterpolator(this, android.R.anim.accelerate_decelerate_interpolator);
imageView.startAnimation(rotateAnimation);
2)平移动画
属性:
fromXDelta 起始点 X 轴坐标,可以是数值、百分数、百分数 p 三种样式,
比如 50、50%、50%p
fromYDelta 起始点 Y 轴从标,可以是数值、百分数、百分数 p 三种样式;
toXDelta 结束点 X 轴坐标
toYDelta 结束点 Y 轴坐标
duration 动画持续时间,以毫秒为单位
fillAfter 如果设置为 true,控件动画结束时,将保持动画最后时的状态
fillBefore 如果设置为 true,控件动画结束时,还原到开始动画前的状态
fillEnabled 与 fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
repeatCount 重复次数
repeatMode 重复类型,有 reverse 和 restart 两个值
reverse 表示倒序回放,restart 表示重新放一遍
必须与 repeatCount 一起使用才能看到效果。
interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等
xml方式:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXDelta="100"
android:fromYDelta="0"
android:interpolator="@android:anim/cycle_interpolator"
android:toXDelta="0"
android:toYDelta="0" />
Java方式:
Animation translateAnimation = new TranslateAnimation(0, 100, 0, 0);
translateAnimation.setDuration(500);
translateAnimation.setInterpolator(this, android.R.anim.cycle_interpolator);
translateAnimation.setFillAfter(true);
imageView.startAnimation(translateAnimation);
3)渐变动画
属性:
(从 0.0 --1.0 ,0.0 表示全透明,1.0 表示完全不透明)
fromAlpha 动画开始的透明度
toAlpha 动画结束时的透明度
duration 动画持续时间,以毫秒为单位
fillAfter 如果设置为 true,控件动画结束时,将保持动画最后时的状态
fillBefore 如果设置为 true,控件动画结束时,还原到开始动画前的状态
fillEnabled 与 fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
repeatCount 重复次数
repeatMode 重复类型,有 reverse 和 restart 两个值,reverse 表示倒序回放,
restart 表示重新放一遍,必须与 repeatCount 一起使用才能看到效果。
因为这里的意义是重复的类型,即回放时的动作。
interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等
xml方式:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="false"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
//使用:
Animation alphaAnimation =
AnimationUtils.loadAnimation(this, R.anim.anim_alpha);
imageView.startAnimation(alphaAnimation);
java方式:
Animation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
alphaAnimation.setDuration(500);
alphaAnimation.setFillAfter(false);
imageView.startAnimation(alphaAnimation);
4)缩放动画
属性:
fromXScale 起始的 X 方向上相对自身的缩放比例,浮点值,比如 1.0 代表自身无变化,0.5 代表起始时缩小一倍,2.0 代表放大一倍;
toXScale 结尾的 X 方向上相对自身的缩放比例,浮点值;
fromYScale 起始的 Y 方向上相对自身的缩放比例,浮点值
toYScale 结尾的 Y 方向上相对自身的缩放比例,浮点值;
pivotX 缩放起点 X 轴坐标
可以是数值、百分数、百分数 p 三种样式,比如 50、50%、50%p
数值时,表示在当前 View 的左上角,即原点处加上 50px,做为起始缩放点;
50%,表示在当前控件的左上角加上自己宽度的 50%做为起始点;
50%p,那么就是表示在当前的左上角加上父控件宽度的 50%做为起始点 x 轴坐标。
pivotY 缩放起点 Y 轴坐标,取值及意义跟 pivotX 一样。
interpolator 指定动画插入器
duration 动画持续时间,以毫秒为单位
fillAfter 如果设置为 true,控件动画结束时,将保持动画最后时的状态
fillBefore 如果设置为 true,控件动画结束时,还原到开始动画前的状态
fillEnabled 与 fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
repeatCount 重复次数
repeatMode 重复类型,有 reverse 和 restart 两个值,reverse 表示倒序回放
restart 表示重新放一遍,必须与 repeatCount 一起使用才能看到效果。因为这里的意义是重复的类型,
即回放时的动作。
interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等
xml方式:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="0"
android:toXScale="1.5"
android:toYScale="1.5" />
java方式:
Animation scaleAnimation = new ScaleAnimation(
0.0f,
1.5f,
0.0f,
1.5f,
Animation.RELATIVE_TO_SELF,
0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
scaleAnimation.setDuration(500);
scaleAnimation.setFillAfter(true);
scaleAnimation.setFillBefore(false);
scaleAnimation.setRepeatCount(3);
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setStartOffset(0);
imageView.startAnimation(scaleAnimation);
5)组合动画
xml方式:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="500"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
<scale
android:duration="500"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="0"
android:toXScale="1.5"
android:toYScale="1.5" />
</set>
AnimationSet animationSet = (AnimationSet) AnimationUtils.loadAnimation
(this, R.anim.anim_set);
imageView.startAnimation(animationSet);
java方式:
AnimationSet animationSet = new AnimationSet(true);
Animation alphaAnimation = new AlphaAnimation(1.0f, 0.1f);
alphaAnimation.setDuration(500);
Animation scaleAnimation = new ScaleAnimation
(0.0f, 1.5f, 0.0f, 1.5f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(500);
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setStartOffset(0);
//不同类型动画加入到组合动画的容器中-startAnimation
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
imageView.startAnimation(animationSet);
6)动画监听
rotateAnimation.setAnimationListener(new Animation.AnimationListener() {
//动画开始前
@Override
public void onAnimationStart(Animation animation) {
}
//动画结束
@Override
public void onAnimationEnd(Animation animation) {
}
//动画重复时
@Override
public void onAnimationRepeat(Animation animation) {
}
});