Android动画1--补间动画、帧动画和属性动画

Android中的动画有三种,分别是补间动画、帧动画、属性动画。

Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;

Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效;

Property Animation(属性动画)是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大。

Frame Animation(帧动画)

1、介绍

优点:使用简单、方便

缺点:容易引起 OOM,因为会使用大量 & 尺寸较大的图片资源

2、使用

方式1:XML实现

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

res/drawable/anim_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="false">
    <!--图片格式必须是png-->
    <item
        android:drawable="@drawable/l1"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l2"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l3"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l4"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l5"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l6"
        android:duration="300"/>
    <item
        android:drawable="@drawable/l7"
        android:duration="300"/>

</animation-list>

步骤2、设置动画资源(图片资源)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start"/>

    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="stop"/>

    <ImageView
        android:id="@+id/mIvImg"
        android:layout_marginTop="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_width="200dp"
        android:layout_height="200dp"/>

</LinearLayout>

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

public class FrameAnimationActivity extends Activity{
    @BindView(R.id.start)
    Button start;
    @BindView(R.id.stop)
    Button stop;
    @BindView(R.id.mIvImg)
    ImageView mIvImg;

    private AnimationDrawable animationDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animationdrawable);

        ButterKnife.bind(this);

        mIvImg.setBackgroundResource(R.drawable.anim_drawable);
        animationDrawable = (AnimationDrawable)mIvImg.getBackground();
    }

    @OnClick({R.id.start,R.id.stop})
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start:
                start();
                break;
            case R.id.stop:
                stop();
                break;
            default:
                break;
        }
    }
    private void start(){
        animationDrawable.start();
    }
    private void stop(){
        animationDrawable.stop();
    }

}

方式2:在Java代码中实现

步骤 1、设置动画资源

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start"/>

    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="stop"/>

    <ImageView
        android:id="@+id/mIvImg"
        android:layout_marginTop="50dp"
        android:layout_gravity="center_horizontal"
        android:layout_width="200dp"
        android:layout_height="200dp"/>

</LinearLayout>
步骤 2、java代码动态加载

public class FrameAnimationActivity1 extends Activity{
    @BindView(R.id.start)
    Button start;
    @BindView(R.id.stop)
    Button stop;
    @BindView(R.id.mIvImg)
    ImageView mIvImg;

    private AnimationDrawable animationDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animationdrawable1);

        ButterKnife.bind(this);
    }

    @OnClick({R.id.start,R.id.stop})
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start:
                start();
                break;
            case R.id.stop:
                stop();
                break;
            default:
                break;
        }
    }
    private void start(){
        //创建帧动画
        animationDrawable = new AnimationDrawable();
        //添加帧
        animationDrawable.addFrame(getResources().getDrawable(R.drawable.l1), 300);
        animationDrawable.addFrame(getResources().getDrawable(R.drawable.l2), 300);
        animationDrawable.addFrame(getResources().getDrawable(R.drawable.l3), 300);
        animationDrawable.addFrame(getResources().getDrawable(R.drawable.l4), 300);
        animationDrawable.addFrame(getResources().getDrawable(R.drawable.l5), 300);
        //设置动画是否只播放一次, 默认是false
        animationDrawable.setOneShot(false);
        //根据索引获取到那一帧的时长
        int duration = animationDrawable.getDuration(2);
        //根据索引获取到那一帧的图片
        Drawable drawable = animationDrawable.getFrame(0);
        //判断是否是在播放动画
        boolean isRunning = animationDrawable.isRunning();
        //获取这个动画是否只播放一次
        boolean isOneShot = animationDrawable.isOneShot();
        //获取到这个动画一共播放多少帧
        int framesCount = animationDrawable.getNumberOfFrames();
        //把这个动画设置为background,兼容更多版本写下面那句
        mIvImg.setBackground(animationDrawable);
        mIvImg.setBackgroundDrawable(animationDrawable);

        animationDrawable.start();
    }

    private void stop(){
        animationDrawable.stop();
    }

}

Tween Animation(补间动画)

View动画是一种渐进式动画,定义动画开始和结束的两帧,并指定动画变化的时间和方式。并通过平移、缩放、旋转和透明度四种效果结合成复杂的动画效果。
而在开始和结束帧之间插入的渐变值依据的是插值器。

1、 应用场景

(1)、标准的动画效果
补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度;
除了常规的动画使用,补间动画还有一些特殊的应用场景。
(2)、 特殊的应用场景
Activity 的切换效果
Fragement 的切换效果

视图组(ViewGroup)中子元素的出场效果

2、 应用

步骤1、创建动画效果

res/anim/rotate_demo.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="2000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360">
</rotate>

步骤2、创建资源布局

res/layout/activity_tweenanimation.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
        android:id="@+id/mcreateRotateAnimation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="旋转"/>

    <Button
        android:id="@+id/mcreateScaleAnimation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="放大缩小"/>

    <Button
        android:id="@+id/mcreateTranslateAnimation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="平移"/>

    <Button
        android:id="@+id/mcreateAlphaAnimation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="透明"/>

    <Button
        android:id="@+id/mcreateSetAnimation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="组合"/>


    <ImageView
        android:id="@+id/mTv"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/l2"/>


</LinearLayout>

步骤3、java代码触发动画

/**
 * 创建旋转动画
 */
private void createRotateAnimation() {
    // 步骤2:创建 动画对象 并传入设置的动画效果xml文件
    Animation ratateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate_demo);
    // 步骤3:播放动画
    mTv.startAnimation(ratateAnimation);

    // 步骤4:监听动画
    ratateAnimation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            Log.e(tag, "1=================Start");
        }
        @Override
        public void onAnimationRepeat(Animation animation) {
            Log.e(tag, "1=================Repeat");
        }
        @Override
        public void onAnimationEnd(Animation animation) {
            Log.e(tag, "1=================End");
        }
    });
}


Property Animation(属性动画)

数值发生器 -- ValueAnimator类

定义:属性动画机制中 最核心的一个类
实现动画的原理:通过不断控制 值 的变化,再不断 手动 赋给对象的属性,从而实现动画效果。
从上面原理可以看出:ValueAnimator类中有3个重要方法:
ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)


1、ValueAnimator.ofInt(int values)
作用:将初始值 以整型数值的形式 过渡到结束值

即估值器是整型估值器 - IntEvaluator


估值器 -- TypeEvaluator

插值器(Interpolator)决定 值 的变化模式(匀速、加速blabla)


估值器 -- TypeEvaluator

估值器(TypeEvaluator)决定 值 的具体变化数值


举例-- ValueAnimator.ofInt

  private void doAnimator() {
        final int top = m1.getTop();
        final int left = m1.getLeft();
        final int width = m1.getMeasuredWidth();
        final int height = m1.getMeasuredHeight();
        ValueAnimator animator = ValueAnimator.ofInt(0, 400,0,300,0,200,0,100,0,50,0,40,0,30,0,20,0,10,0,5,0);
        // 设置动画运行的时长
        animator.setDuration(4000);
        //多久后开始动画
        animator.setStartDelay(0);
        //循环次数
        animator.setRepeatCount(5);
        //无穷循环
//        animator.setRepeatCount(ValueAnimator.INFINITE);
        //repeat的时候正向重新计算
        animator.setRepeatMode(ValueAnimator.RESTART);
        //repeat的时候反向重新计算
//        animator.setRepeatMode(ValueAnimator.REVERSE);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                // 获得改变后的值
                int value = (int) valueAnimator.getAnimatedValue();
                // 将改变后的值赋给对象的属性值
                m1.layout(left,top-value,left+width,top-value+height);
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                Log.e(tag,"onAnimation   Start");
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                Log.e(tag,"onAnimation   End");
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                Log.e(tag,"onAnimation   Cancel");
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
                Log.e(tag,"onAnimation   Repeat");
            }
        });
        animator.start();
    }


举例-- 插值器和估值器

/**
 * 抛物线
 * @param view
 */
public void paowuxian(View view)
{
    ValueAnimator valueAnimator = new ValueAnimator();
    valueAnimator.setDuration(3000);
    valueAnimator.setObjectValues(new PointF(0, 0));
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.setEvaluator(new TypeEvaluator<PointF>()
    {
        // fraction = t / duration
        @Override
        public PointF evaluate(float fraction, PointF startValue,
                               PointF endValue)
        {
            Log.e(tag, fraction * 3 + "");
            // x方向200px/s ,则y方向0.5 * 10 * t
            PointF point = new PointF();
            point.x = 200 * fraction * 3;
            point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
            return point;
        }
    });

    valueAnimator.start();
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            PointF point = (PointF) animation.getAnimatedValue();
            m1.setX(point.x);
            m1.setY(point.y);

        }
    });
    valueAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
            Log.e(tag,"onAnimation   Start");
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            Log.e(tag,"onAnimation   End");
        }

        @Override
        public void onAnimationCancel(Animator animator) {
            Log.e(tag,"onAnimation   Cancel");
        }

        @Override
        public void onAnimationRepeat(Animator animator) {
            Log.e(tag,"onAnimation   Repeat");
        }
    });
}

源码:
https://github.com/yuanhhyuan/UI4



参考文章:

Android 逐帧动画:关于 逐帧动画 的使用都在这里了!

https://www.jianshu.com/p/225fe1feba60

Android 动画:手把手教你使用 补间动画

https://www.jianshu.com/p/733532041f46

Property Animation(属性动画)
https://www.jianshu.com/p/2412d00a0ce4

猜你喜欢

转载自blog.csdn.net/haobobo710/article/details/80884640