第七章

 1. 视图动画(View 动画)

  • Animation 框架定义了透明度AlphaAnimation, 旋转RotateAnimation, 缩放ScaleAnimation和位移TranslateAnimation几种常见的动画。
  • 控制的是整个View, 实现原理是每次绘制视图时View所在的ViewGroup中的drawChild方法获取该View的Animation的Transformation值,然后调用canvas.concat(transformationToApply.getMatrix()),通过矩阵运算完成动画帧。如果动画没有完成,就继续调用invalidate方法,启动下次绘制来驱动动画,从而完成整个动画的绘制。
  • 视图动画的问题在于当View 发生变化后,响应时间还停留在之前的位置
  • AnimationSet 动画集合
  • AnimationListener 设置动画的监听回调方法

2.属性动画

  • 3.0 之后新增了属性动画(Animator框架),使用的最多的是AnimatorSet 和 ObjectAnimator 配合
    ,使用ObjectAnimator进行更精细化的控制,只控制一个对象的一个属性,而使用多个ObjectAnimator组合到AnumatorSet 形成一个动画。而且ObjectAnimator 能够自动驱动,调用setFragmeDely(longframeDelay) 设置动画帧之间的间隙,在不影响动画效果的情况下减少CPU 资源消耗

  • ObjectAnimator

    • 创建通过静态工厂类直接返回一个ObjectAnimator 对象,参数包括一个对象和对象的属性名字,但这个属性必须有get 和 set 方法,内部会通过Java 反射调用set 函数修改对象属性值。同样也可以调用 setInterpolator 设置相应的插值器。常用的可以直接使用的属性动画的属性包括以下:
    • translationX和translationY:控制view从它布局容器左上角坐标偏移的位置;
    • rotation、rotationX和rotationY:控制view围绕支点进行2D和3D旋转;
    • scaleX和scaleY:控制view围绕着它的支点进行2D缩放;
    • pivotX和pivotY:控制支点位置,围绕这个支点进行旋转和缩放处理。默认情况下,支点是view的中心点;
    • x和y:控制view在它的容器中的最终位置,它是最初的左上角坐标和translationX、translationY的累计和;
    • alpha:控制透明度,默认是1(不透明)
  • 如果一个属性没有get,set方法,可以自顶一个一个Wrapper类,简介的给属性提供get/ set方法

 private static class WrapperView {
        private View mTragetView;

        public WrapperView(View traget) {
            mTragetView = traget;
        }

        public int getWidth() {
            return mTragetView.getLayoutParams().width;
        }

        public void setWidth(int width) {
            mTragetView.getLayoutParams().width = width;
            mTragetView.requestLayout();
        }
    }

    // 调用方法
    WrapperView wrapperView = new WrapperView(mButton);
    ObjectAnimator animator = ObjectAnimator.ofFloat(wrapperView, "translationX", 300);
    animator.setDuration(1000);
    animator.start();
  • PropertyValuesHolder
    • 类似视图动画中的AnimationSet,在属性动画中,如果针对同一个对象的多个属性,要同时作用多种动画可以使用PropertyValuesHolder
 PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300);
        PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
        PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
        ObjectAnimator.ofPropertyValuesHolder(mImageViews.get(0), pvh1, pvh2, pvh3).setDuration(1000).start();
  • ValueAnimator

    • ValueAnimator 在属性中非常重要,ObjectAnimator 也是继承自它,它本身不提供任何动画效果,更像是数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程。可以在ValueAnimator 的 AnimatorUpdateListener 中监听数值的变化, 从而完成动画的变换。
  • 动画的监听

    • 一个完整的动画有Start, Repeat , End , Cancel 四个过程,通过Android提供了接口,大部分时候我们只关注onAnimationEnd 事件,所有Android 也提供了一个AnimatorListenerAdapter来让我们选择必要的事件进行监听
// 向左移动200
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4),
                "translationX", -200F);
        animator4.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

animator4.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
  • AnimatorSet

    • 对一个属性同时作用多个属性动画效果,前面的PropertyValuesHolder 实现了这样的效果。而AnimatorSet 不仅能实现,爱能够实现更为精准的顺序控制。通过 playTogether, playSequentially, animSet.play(),with().before(),after() 这些方法控制多个动画的协同
  • 在XML 中使用属性动画

    • 这个属性动画必须建在animator 文件夹下(Animator),anim文件夹下不起作用(Animation)
<?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="2.0"
    android:valueType="floatType">

</objectAnimator>
    // 调用xml文件中的属地动画
    Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scale_x);
    animator.setTarget(mImageViews.get(0));
    animator.start();
  • 在Android 3.0 之后,View 增加了 animate 方法来直接驱动属性动画,可以理解为属性动画的简写方法
imageView.animate().alpha(0).y(100).setDuration(1000)
        .setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
  • 布局动画
    • 布局动画是指作用在ViewGroup 上,给ViewGroup 增加View 时添加一个动画过度效果。
    • 最简单的是在ViewGroup 的xml 中新增 android:animateLayoutChanges=”true”,这样当ViewGroup 添加子View的时候,子View会呈现逐渐显示的过渡效果,这个是Android默认的效果切无法替换
    • 可以通过LayoutAnimationController 类来自定义一个子View 的过度效果
    • LayoutAnimationController 第一个参数是需要作用的动画,第二个参数是每个子View的delay事件。当delay事件不为0时,可以设置子View显示的顺序
      • LayoutAnimationController.ORDER_NORMAL 顺序
      • LayoutAnimationController.ORDER_RANDOM 随机
      • LayoutAnimationController.ORDER_REVERSE 反序
// 设置子View 的过度动画效果
        LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
        // 设置过渡效果
        ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
        sa.setDuration(2000);
        // 设置布局动画的显示属性
        LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5F);
        lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
        // 为ViewGroup 设置布局动画
  • Interpolator (插值器)
    • 这部分可参考文档, 常用的也没有几个插值

  • 自定义动画
    • 创建自定义动画,只需要实现它的applyTransformation 的逻辑就可以了,不过通常还需要覆盖父类的initialize方法来实现初始化工作。
    • applyTransformation(float interpolatedTime,Transformation t) 第一个参数是插值器的时间因子,第二个是矩阵的封装类 一般用这个类获得当前的矩阵对象

  • SVG 动画

    • Android 在 5.x之后增加了对SVG适量图形的支持

      先了解一下什么是SVG:

    • 可伸缩矢量图形(Scaleable Vector Graphics)

    • 定义用于网格的机遇矢量的图形

    • 使用XML 格式定义图形

    • 图像在放大或改变尺寸的情形下其图形质量不会有所损失

    • 万维网联盟的标准

    • 与DOM 和 XSL 之类的 W3C 标准是一个整体

  • 使用 标签创建SVG,就像用指令控制一只画笔,例如移动画笔到某一坐标,画一条线,画一条曲线等。 标签所支持的指定有以下几种:

    • M = moveto(M X,Y) ; 将画笔移动到指定的坐标位置,未发生绘制
    • L = lineto(L X,Y); 画直线到指定的坐标位置
    • H = horizontal lineto(H X) ; 画水平线到指定的X坐标位置
    • V = vertical lineto(V Y); 画垂直线到指定的Y坐标
    • C = curveto(C X1, Y1, X2, Y2, ENDX, ENDY) ; 三次贝塞尔曲线
    • S = smooth curveto(S, X2, Y2, ENDX, ENDY) 三次贝塞尔曲线
    • Q = quadratic Belzier curve(Q X,Y, ENDX, ENDY) 二次贝塞尔曲线
    • T = smooth quadratic Belzier curveto(T ENDX, ENDY) 映射前面路径后的终点
    • A = elliptical Arc(A, RX, RY, XROTATION, FLAG1, FLAG2, X, Y) 弧线
    • Z = closepath(); 关闭路径
  • 注意事项

    • 坐标轴以(0,0) 为中心,x轴向右,y轴向下
    • 所有指令大小写均可,大写绝对定位,参照全局坐标系,小写相对定位,操作父容器坐标系
    • 指令和数据间的空格可以省略
    • 同一指令出现多次可以只用一个
  • SVG 参数的写法固定且复杂,完全可以使用程序实现,所以一般通过SVG 编辑器来编辑SVG 图形。
    书中给出了一个编辑的网站

  • Android 中使用SVG

    • Google 在 5.x 后提供了两个新的API 来帮助支持SVG :VectorDrawable, AnimatedVerctorDrawable。其中 VectorDrawable 让你可以创建基于XML 的SVG 图形,并结合AnimatedVectorDrawable 来实现动画效果.具体的实现效果可以参考demo

GithubDemo地址



Android      Android

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!