是时候整理下android动画了,补间动画、属性动画、逐帧动画

1,007 阅读4分钟

网上搜集了一下android动画的资料,大都是16、17年的文章,很基础的知识,而且还特别的重要,废话不多说,赶快整理吧

1. 补间动画

补间动画由 Animation 类来实现具体效果,包括

  • 平移(TranslateAnimation)
  • 缩放(ScaleAnimation)
  • 旋转(RotateAnimation)
  • 透明度(AlphaAnimation) 四个子类,四种变化,但补间动画只是达到了其视觉效果,并不是真正的位置上的变化。(属性动画出来之后,补间动画就不那么常用了)。

2. 属性动画

Animator -ValueAnimator 属性的值变了 视觉没变
-ObjectAnimator 属性、视觉都改变了
-TimeAnimator
属性动画是真正的改变了属性的值

2.1 ObjectAnimator

例如: (1)、系统属性alpha 透明度 scaleX横向拉伸 scaleY纵向拉伸 translationX 横向移动 translationY 纵向移动rotation,rotationx rotationy 旋转
PS:我们我们设置的参数必须是View中有Set方法,比如scaleX,View中有setScaleX()方法

(2)、自定义控件属性 这个属性必须实现set get方法

(3)、使用属性动画改变控件透明度

//透明度alpha
    public void test1(){
        /*
            1.target 需要动画的控件
            2、propertyName 控件的那个属性
            3、...values  变化的值 start - end
         */
        ObjectAnimator alphaAni = ObjectAnimator.ofFloat(v,"alpha",1,0);
        alphaAni.setDuration(1000);
        alphaAni.start();
    }

4)、使用属性动画使控件旋转

//旋转
public void test2(){	
	ObjectAnimator rotateAni = ObjectAnimator.ofFloat(v,"rotation",0,360);
	rotateAni.setDuration(1000);
	rotateAni.start();
}

(5)、使用属性动画进行缩放

 public void test3(){
	ObjectAnimator scaleAniX = ObjectAnimator.ofFloat(v,"scaleX",1,1.1f,1.1f,1);
	scaleAniX.setDuration(1000);
	scaleAniX.setRepeatCount(-1);
	scaleAniX.setRepeatMode(ValueAnimator.RESTART);

	ObjectAnimator scaleAniY = ObjectAnimator.ofFloat(v,"scaleY",1,1.1f,1.1f,1);
	scaleAniY.setDuration(1000);
	scaleAniY.setRepeatCount(-1);
	scaleAniY.setRepeatMode(ValueAnimator.RESTART);
}

(6)、使用属性动画进行平移

 public void test4(){
	ObjectAnimator translationY = ObjectAnimator.ofFloat(v,"translationY",0f, 20f);
        translationY.setDuration(1000);
	translationY.start();
}

(7)、注意
属性动画中,
with 同时执行
after 后面执行
before 前面执行
playTogether 同时执行
playSequence 顺序执行
与补间动画相同的是,同样使用AnimatorSet方法给同一控件添加多个动画

AnimatorSet aSet = new AnimatorSet();
aSet.playTogether(scaleAniX,scaleAniY);
aSet.start();

2.2 ValueAnimator

ValueAnimator是针对值的,这个不会对控件做任何操作,我们可以设置它在某个值运动到另一个值,通过监听它的值变化来操作控件。

ValueAnimator的简单使用 (1)创建ValueAnimator实例

ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 200);
valueAnimator.setDuration(2000);
valueAnimator.start();

(2)添加监听 上面三行代码实现了值的动画变化,我们来添加监听:

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int value = (int) animation.getAnimatedValue();
        // 具体可以可以改变LinearLayout的宽度
        llBox.getLayoutParams().width = (int) animation.getAnimatedValue();
        llBox.requestLayout();
        Log.e(TAG, "value:" + value);
    }
});


(3)移除监听器

/**
 * 移除AnimatorUpdateListener
 */
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
 /**
  * 移除AnimatorListener
  */
void removeListener(AnimatorListener listener);
void removeAllListeners();
/**
  * 移除AnimatorPauseListener 
  */
void removePauseListener(AnimatorPauseListener listener)


2.3 ViewPropertyAnimator

ViewPropertyAnimator也是属性动画,使用方便快捷,如

view.animate().scaleX(1.2f).scaleY(0.1f).translationX(100f).translationY(50f).setDuration(100).start()

特别是,可以将值设为偏移0、旋转0、放大1快速将属性动画效果恢复到初始状态

3. # 逐帧动画

1. 作用对象

视图控件(View)

如Android的TextView、Button等等
不可作用于View组件的属性,如:颜色、背景、长度等等

2. 原理

将动画拆分为 帧 的形式,且定义每一帧 = 每一张图片
逐帧动画的本质:按序播放一组预先定义好的图片

3. 具体使用

步骤1:将动画资源(即每张图片资源)放到 drawable文件夹里

技巧: 找到自己需要的gif动画 用 gif分解软件(如 GifSplitter)将 gif 分解成一张张图片即可

aHR0cDovL3VwbG9hZC1pbWFnZXMuamlhbnNodS5pby91cGxvYWRfaW1hZ2VzLzk0NDM2NS04MGZkMzBmNjBkN2Y3NTc5LmdpZj9pbWFnZU1vZ3IyL2F1dG8tb3JpZW50L3N0cmlw.gif

步骤2:设置 & 启动 动画

设置 & 启动 逐帧动画有两种方式:在XML / Java代码。

方式1:XML实现

步骤1:在 res/anim的文件夹里创建动画效果.xml文件

此处路径为res/anim/knight_attack.xml

步骤2:设置动画资源(图片资源) knight_attack.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true" // 设置是否只播放一次,默认为false
    >

// item = 动画图片资源;duration = 设置一帧持续时间(ms)
    <item android:drawable="@drawable/a0" android:duration="100"/>
    <item android:drawable="@drawable/a1" android:duration="100"/>
    <item android:drawable="@drawable/a2" android:duration="100"/>
    <item android:drawable="@drawable/a3" android:duration="100"/>
    <item android:drawable="@drawable/a4" android:duration="100"/>
    <item android:drawable="@drawable/a5" android:duration="100"/>
    <item android:drawable="@drawable/a6" android:duration="100"/>
    <item android:drawable="@drawable/a7" android:duration="100"/>
    <item android:drawable="@drawable/a8" android:duration="100"/>
    <item android:drawable="@drawable/a9" android:duration="100"/>
    <item android:drawable="@drawable/a10" android:duration="100"/>
    <item android:drawable="@drawable/a11" android:duration="100"/>
    <item android:drawable="@drawable/a12" android:duration="100"/>
    <item android:drawable="@drawable/a13" android:duration="100"/>
    <item android:drawable="@drawable/a14" android:duration="100"/>
    <item android:drawable="@drawable/a15" android:duration="100"/>
    <item android:drawable="@drawable/a16" android:duration="100"/>
    <item android:drawable="@drawable/a17" android:duration="100"/>
    <item android:drawable="@drawable/a18" android:duration="100"/>
    <item android:drawable="@drawable/a19" android:duration="100"/>
    <item android:drawable="@drawable/a20" android:duration="100"/>
    <item android:drawable="@drawable/a21" android:duration="100"/>
    <item android:drawable="@drawable/a22" android:duration="100"/>
    <item android:drawable="@drawable/a23" android:duration="100"/>
    <item android:drawable="@drawable/a24" android:duration="100"/>
    <item android:drawable="@drawable/a25" android:duration="100"/>
</animation-list>

步骤3:在Java代码中载入 & 启动动画


public class FrameActivity extends AppCompatActivity {
    private Button btn_startFrame,btn_stopFrame;
    private ImageView iv;
    private AnimationDrawable animationDrawable;

        iv = (ImageView) findViewById(R.id.iv);
        btn_startFrame = (Button) findViewById(R.id.btn_startFrame);
        btn_stopFrame = (Button) findViewById(R.id.btn_stopFrame);


        <-- 开始动画 -->
        btn_startFrame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                iv.setImageResource(R.drawable.knight_attack);
                // 1. 设置动画
                animationDrawable = (AnimationDrawable) iv.getDrawable();
                // 2. 获取动画对象
                animationDrawable.start();
                // 3. 启动动画
            }
        });
        //停止动画
        btn_stopFrame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                iv.setImageResource(R.drawable.knight_attack);
                // 1. 设置动画
                animationDrawable = (AnimationDrawable) iv.getDrawable();
                // 2. 获取动画对象
                animationDrawable.stop();
                // 3. 暂停动画
            }
        });

    }
}


方式2:在Java代码中实现

        <-- 直接从drawable文件夹获取动画资源(图片) -->
        animationDrawable = new AnimationDrawable();
        for (int i = 0; i <= 25; i++) {
            int id = getResources().getIdentifier("a" + i, "drawable", getPackageName());
            Drawable drawable = getResources().getDrawable(id);
            animationDrawable.addFrame(drawable, 100);
        }

        <-- 开始动画 -->
        btn_startFrame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animationDrawable.setOneShot(true);
                iv.setImageDrawable(animationDrawable);
                // 获取资源对象
                animationDrawable.stop();
                 // 特别注意:在动画start()之前要先stop(),不然在第一次动画之后会停在最后一帧,这样动画就只会触发一次
                animationDrawable.start();
                // 启动动画
               
            }
        });

         <-- 停止动画 -->
        btn_stopFrame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animationDrawable.setOneShot(true);
                iv.setImageDrawable(animationDrawable);
                animationDrawable.stop();
            }
        });



4. 特点

优点:使用简单、方便
缺点:容易引起 OOM,因为会使用大量 & 尺寸较大的图片资源
尽量避免使用尺寸较大的图片

5. 应用场景

较为复杂的个性化动画效果。

使用时一定要避免使用尺寸较大的图片,否则会引起OOM

6. AnimationUtils使用

例如

private fun showAnimation(bottomView: View, rootView: View) {
    val open = AnimationUtils.loadAnimation(this, R.anim.bottom_slide_in)
    val alpha = AnimationUtils.loadAnimation(this, R.anim.alpha_in_3)
    bottomView.startAnimation(open)
    rootView.startAnimation(alpha)
}

bottom_slide_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="300"
           android:fromYDelta="100%p"
           android:toYDelta="0"
    />

参考: # Android 动画:逐帧动画,补间动画和属性动画
# Android属性动画和补间动画的区别
# Android 逐帧动画:关于 逐帧动画 的使用都在这里了!
# Android动画篇(三)—— 属性动画ValueAnimator的使用 # ObjectAnimator 动画取消并恢复原位