欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android补间、逐帧动画

程序员文章站 2022-03-25 14:50:05
...

目录

 

1.逐帧动画

1)AnimationDrawable实现

2)SurfaceView实现

2.补间动画

1)旋转动画

2)平移动画

3)渐变动画

4)缩放动画

5)组合动画

6)动画监听


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();
    }
}

内存情况也比较稳定:

Android补间、逐帧动画

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方式:

Android补间、逐帧动画

 前两个构造,都是旋转角度,加上设置旋转中心。最后一个构造,可以设置旋转动画的参考系,看如下示例:

//设置旋转参考系为自身中心点
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) {
            }
        });