动画机制-《Android群英传》

动画分为视图动画和属性动画框架。

  • 视图动画:
    • 提供AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四种动画方式
    • 提供动画合集AnimationSet,用于动画混合
    • 缺点显著:不具备交互性,只能做普通的动画效果
    • 优点:效率高、使用方便
  • 属性动画框架:更加丰富的动画效果。

常见问题

  1. 视图动画和属性动画优缺点
  2. 视图动画的使用
  3. 属性动画的使用
  4. ObjectAnimator、AnimatorSet、PropertyValuesHolder、ValueAnimator的作用
  5. 如何利用xml使用属性动画
  6. 动画事件有哪些?
  7. 布局动画是什么?
  8. 插值器Interpolators的作用
  9. SVG是什么?
  10. SVG和Bitmap的区别
  11. 如何在Android中使用SVG(VectorDrawable和VectorDrawable)?

1-视图动画实例

展现4种动画效果

1-布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_weight="3"
    tools:context="com.example.administrator.featherdemos.Activity.AnimationSetActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="1"
        android:weightSum="2">

        <ImageView
            android:id="@+id/animationset_imageview1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:src="@drawable/jide"
            android:layout_weight="1"
            android:layout_centerInParent="true"/>

        <ImageView
            android:id="@+id/animationset_imageview2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:src="@drawable/jide"
            android:layout_weight="1"
            android:layout_centerInParent="true"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="1"
        android:weightSum="2">

        <ImageView
            android:id="@+id/animationset_imageview3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:src="@drawable/jide"
            android:layout_weight="1"
            android:layout_centerInParent="true"/>

        <ImageView
            android:id="@+id/animationset_imageview4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:src="@drawable/jide"
            android:layout_weight="1"
            android:layout_centerInParent="true"/>

    </LinearLayout>

    <ImageView
        android:id="@+id/animationset_set_imageview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:src="@drawable/jide"
        android:layout_weight="1"
        />
</LinearLayout>

2-Activity

public class AnimationSetActivity extends Activity {

    ImageView imageView1;
    ImageView imageView2;
    ImageView imageView3;
    ImageView imageView4;
    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation_set);

        imageView1 = (ImageView) findViewById(R.id.animationset_imageview1);
        imageView2 = (ImageView) findViewById(R.id.animationset_imageview2);
        imageView3 = (ImageView) findViewById(R.id.animationset_imageview3);
        imageView4 = (ImageView) findViewById(R.id.animationset_imageview4);
        imageView = (ImageView) findViewById(R.id.animationset_set_imageview);
        //透明度
        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setDuration(2000);
        imageView1.setAnimation(alphaAnimation);
        //旋转
        RotateAnimation rotateAnimation = new RotateAnimation(0, 10);
        rotateAnimation.setDuration(2000);
        imageView2.setAnimation(rotateAnimation);
        //缩放
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 1, 0.5f, 1);
        scaleAnimation.setDuration(2000);
        imageView3.setAnimation(scaleAnimation);
        //平移
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 50, 0, 50);
        translateAnimation.setDuration(2000);
        imageView4.setAnimation(translateAnimation);

        /*
        *  动画集合,可以混合多种动画效果。
        * */
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.setDuration(3000);
        animationSet.addAnimation(alphaAnimation);
        animationSet.addAnimation(rotateAnimation);
        imageView.setAnimation(animationSet);
    }
}

2-属性动画

Animator框架中最多的就是AnimatorSet和ObjectAnimator。ObjectAnimator控制一个对象的一个属性,将多个ObjectAnimator组合成AnimatorSet形成动画。

属性值作用
translationX、translationY控制View从左上角偏移的位置
rotation、rotationX、rotationY控制View围绕支点做2D和3D旋转
scaleX、scaleY围绕支点2D缩放
pivotX、pivotY控制支点位置,默认为View中心
x、y描述View的最终位置
alpha透明度,默认1不透明,0为完全透明
  • 要操作的View的属性,必须要有get和set方法。
  • 如果没有get、set方法,需要使用装饰者模式包装获得get、set;或者通过后面的ValueAnimator实现。

1-实例

ImageView imageView = (ImageView) findViewById(R.id.animator_imageview);

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,
                "translationY", 300);
        objectAnimator.setDuration(2000);
        objectAnimator.start();

2-没有get、set方法

实现包装类

    private class WrapperView{
        private View view;
        public WrapperView(View view){
            this.view = view;
        }
        public int getWidth(){
            return view.getLayoutParams().width;
        }
        public void setWidth(int width){
            view.getLayoutParams().width = width;
            view.requestLayout();
        }
    }

使用包装类实现属性动画

WrapperView wrapperView = new WrapperView(imageView);
ObjectAnimator.ofInt(wrapperView, "width", 500).setDuration(2000).start();

3-PropertyValuesHolder

类似于AnimationSet的作用,将多种效果共同作用于对象。

PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationY", 200);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(imageView, pvh1, pvh2, pvh3).setDuration(1000).start();

4-ValueAnimator

ObjectAnimator的父类,提供数值变化和监听,本身不完成动画,通过得到的数值可以去进行一定变换。

        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100);
        valueAnimator.setTarget(imageView);
        valueAnimator.setDuration(1000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Float value = (Float) valueAnimator.getAnimatedValue();
                //使用数值去完成数值的变换
            }
        });

1-实例:数字自动增加(0~100)

TextView textView = (TextView) findViewById(R.id.count_textview);

textView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
            //数值动画从0~100增长
                ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        //使用获取的数值,显示在TextView(数值自动增长)
                        textView.setText((Integer) valueAnimator.getAnimatedValue()+"");
                    }
                });
            //动画在3s内完成
                valueAnimator.setDuration(3000);
                valueAnimator.start();
   }
});

5-动画监听

有start、repeat、end、cancel四个过程,可以监听。

//监听全部步骤
objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
//选择性监听
objectAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });

6-AnimationSet

可以和PropertyValuesHolder将动画融合,在此基础上还可以控制动画的顺序。

        ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView,"translationY", 300);
        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView,"scaleX", 1f, 0, 1f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(objectAnimator1, objectAnimator2);
        animatorSet.setDuration(2000);
        animatorSet.start();

7-在XML中使用属性动画

  • 需要在res文件夹中创建animator文件夹!!

XML文件

在X轴上缩放,从1.0>0.5

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="0.5"
    android:valueType="floatType">

</objectAnimator>

从XML中加载animator

        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scalex);
        animator.setTarget(imageView);
        animator.start();

8-View直接使用animate()

是属性动画的一种简写形式。

        imageView.animate() //获得animator
                .alpha(0)
                .y(300)
                .setDuration(3000)
                .withStartAction(new Runnable() {
                    @Override
                    public void run() {
                    }
                })
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {
                        //结束动作后,在UI线程操作
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                            }
                        });
                    }
                })
                .start(); //开始

3-布局动画

通过给ViewGroup设置布局动画,达到View逐渐呈现的过渡效果。
android:animateLayoutChanges="true"者可以给布局添加系统默认的效果。
如果要自定义过渡效果,需要通过LayoutAnimationController类来自定义,本质是给布局一个视图动画,在View出现时产生过渡效果。

LinearLayout mLinear  = (LinearLayout) findViewById(R.id.mLinear);
//设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0,1,0,1);
 sa.setDuration(1000);
//设置布局动画的显示属性
//第一个参数,是需要作用的动画,而第二个参数,则是每个子View显示的delay时间
LayoutAnimationController lac = new LayoutAnimationController(sa,0.5f);        lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
//为ViewGroup设置布局动画
mLinear.setLayoutAnimation(lac);

当delay的时间不为0时,可以设置子View显示的顺序:

  • LayoutAnimationController.ORDER_NORMAL——顺序
  • LayoutAnimationController.ORDER_RANDOM——随机
  • LayoutAnimationController.ORDER_REVERSE——反序

4-Interpolators(插值器)

插值器可以定义动画的变换速率。可以直接把插值器理解为动画变换的加速度。例如一个位移动画,如果使用线性插值器,那么在持续时间内,单位时间所移动的距离都是一样的;如果使用加速度插值器,那么单位时间内所移动的距离将越来越快。

Interpolator属性实际上是Animation类的一个XML属性,有很多系统值。

转载-Interpolator详细讲解

5-自定义动画

具体内容参考原著或者网上博客。
转载:复杂自定义动画实现

6-Android 5.x SVG矢量动画机制

1-SVG是什么?(Scalable Vetor Graphics)

  • 可伸缩矢量图
  • 定义用于网络的基于矢量的图形
  • 使用XML格式定义图形
  • 图像缩放不会影响质量
  • 万维网联盟标准
  • 与DOM和XSL之类的W3C标准是一个整体

2-SVG和Bitmap区别

  • Bitmap是通过每个像素点上存储色彩信息来表示图像。
    SCG是一个绘图标准。
  • Bitmap放大不会失真。Bitmap需要为不同分辨率设计多套图表,SVG不需要。

3-SVG编辑器

SVG写法固定复杂,可以通过SVG编辑器完成。将图形编辑好后,可以使用编辑器转换为SVG代码。

4-Android中使用SVG

  • VectorDrawable:创建基于XML的SVG图形
  • AnimatedVectorDrawable:实现动画效果

1-VectorDrawable实例

res右击,选择最上面的New,选择Vector Asset
使用系统默认矢量图或者阿里矢量图库下载的矢量图。
创建好后ic_cake_black_24dp.xml如下:(我用系统默认图标)

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <group
        android:name="test">
        <path
            android:fillColor="#FF000000"
            android:pathData="M12,6c1.11,0 2,-0.9 2,-2 0,-0.38 -0.1,-0.73 -0.29,-1.03L12,0l-1.71,2.97c-0.19,0.3 -0.29,0.65 -0.29,1.03 0,1.1 0.9,2 2,2zM16.6,15.99l-1.07,-1.07 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,21c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4.61c-0.56,0.38 -1.23,0.61 -1.96,0.61 -0.92,0 -1.79,-0.36 -2.44,-1.01zM18,9h-5L13,7h-2v2L6,9c-1.66,0 -3,1.34 -3,3v1.54c0,1.08 0.88,1.96 1.96,1.96 0.52,0 1.02,-0.2 1.38,-0.57l2.14,-2.13 2.13,2.13c0.74,0.74 2.03,0.74 2.77,0l2.14,-2.13 2.13,2.13c0.37,0.37 0.86,0.57 1.38,0.57 1.08,0 1.96,-0.88 1.96,-1.96L20.99,12C21,10.34 19.66,9 18,9z"/>
    </group>
</vector>

使用矢量图:

<ImageView
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:src="@drawable/ic_cake_black_24dp"/>

2-AnimatedVectorDrawable实例:动画效果

创建animated-vector标签的文件ic_cake_anim_vector:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_cake_black_24dp">
   <target
       android:animation="@animator/scalex"
       android:name="test">
   </target>
</animated-vector>
  • android:drawable需要使用矢量图
  • android:animation中为objectAnimator的动画效果
  • android:name为矢量图中(在上个实例里)

布局中引用:

<ImageView
            android:id="@+id/svg_anim_imageview"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/ic_cake_anim_vector"/>

开启动画:

ImageView imageView = (ImageView) findViewById(R.id.svg_anim_imageview);
((Animatable)imageView.getDrawable()).start();
  • AnimatedVectorDrawable将静态的VectorDrawable和动态的ObjectAnimator连接起来。

5-SVG做简单动画

将一个横线从中间折断变成“X”的效果

1-绘制初始两条线

vector_two_line.xml

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="200dp"
    android:height="200dp"
    android:viewportWidth="100"
    android:viewportHeight="100">
    <group>
        <path
            android:name="path1"
            android:pathData="M 20,80 L 50,80 80,80"
            android:strokeColor="@color/colorAccent"
            android:strokeWidth="3"
            android:strokeLineCap="round"/>

        <path
            android:name="path2"
            android:pathData="M 20,20 L 50,20 80,20"
            android:strokeColor="@color/colorAccent"
            android:strokeWidth="3"
            android:strokeLineCap="round"/>
    </group>
</vector>

2-动画效果(ObjectAnimator)

path1_animator:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:propertyName="pathData"
    android:valueFrom="M 20,80 L 50,80 80,80"
    android:valueTo="M 20,80 L 50,50 80,80"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">

</objectAnimator>

path2_animator:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200"
    android:propertyName="pathData"
    android:valueFrom="M 20,20 L 50,20 80,20"
    android:valueTo="M 20,20 L 50,50 80,20"
    android:valueType="pathType"
    android:interpolator="@android:anim/bounce_interpolator">

</objectAnimator>

3-粘合静态矢量图和动态动画

vector_two_line_anim.xml

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vector_two_line">
   <target
       android:animation="@animator/path1_animator"
       android:name="path1">
   </target>
   <target
       android:animation="@animator/path2_animator"
       android:name="path2">
   </target>
</animated-vector>

4-使用

<ImageView
    android:id="@+id/two_line_imageview"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:src="@drawable/vector_two_line_anim"/>
ImageView imageView = (ImageView) findViewById(R.id.two_line_imageview);

((Animatable)imageView.getDrawable()).start();

6-SVG:轨迹动画

轨迹动画,这里给上例的两条线在绘制的时候显示轨迹。
动画:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="trimPathEnd"
    android:valueFrom="0"
    android:valueTo="1"
    android:valueType="floatType"
    android:interpolator="@android:interpolator/accelerate_decelerate">

</objectAnimator>

动画粘贴器:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vector_two_line">
   <target
       android:animation="@animator/trimpath_animator"
       android:name="path1">
   </target>
   <target
       android:animation="@animator/trimpath_animator"
       android:name="path2">
   </target>
</animated-vector>

ImageView:

<ImageView
            android:id="@+id/trimpath_anim_imageview"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:src="@drawable/vector_trimpath_anim"/>

使用:

ImageView imageView = (ImageView) findViewById(R.id.trimpath_anim_imageview);
((Animatable)imageView.getDrawable()).start();

这里省略了一些书上的实例,可以自行查阅。大致关于Android动画机制的内容就这么多了,还需要以后深入学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值