Android补间、逐帧动画

目录

 

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

内存情况也比较稳定:

https://img-blog.csdnimg.cn/20190307151238103.png

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

猜你喜欢

转载自blog.csdn.net/qq_37321098/article/details/88303655