安卓

Android26-动画机制与使用技巧

2017-05-25  本文已影响66人  figure_ai

Android View动画

Animation 框架定义了透明度、旋转、缩放和位移几种常见的动画,而且控制的是整个View。

  • 以下是一些常用动画的设置
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void btnAlpha(View view) {
        AlphaAnimation aa = new AlphaAnimation(0, 1);
        aa.setDuration(3000);
        view.startAnimation(aa);
    }
    public void btnRotate(View view) {
        //0 :旋转起始角度
        //360 : 旋转终止角度
        //0,0 :绕那个点旋转
        RotateAnimation ra = new RotateAnimation(0, 270, 0, 0);
        ra.setDuration(3000);
        view.startAnimation(ra);
    }
    public void btnRotateSelf(View view) {
        RotateAnimation ra = new RotateAnimation(0, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        ra.setDuration(3000);
        view.startAnimation(ra);
    }
    public void btnTranslate(View view) {
        //0 : x起始位置
        //200 :x结束位置
        //0 : y起始位置
        //300 :y结束位置
        TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
        ta.setDuration(3000);
        view.startAnimation(ta);
    }
    public void btnScale(View view) {
        //1 : x起始大小
        //1 : x结束大小
        //0 : y起始大小
        //2 : y结束大小
        ScaleAnimation sa = new ScaleAnimation(1, 1, 0, 2);
        sa.setDuration(3000);
        view.startAnimation(sa);
    }
    public void btnScaleSelf(View view) {
        ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        sa.setDuration(3000);
        view.startAnimation(sa);
    }
    public void btnSet(View view) {
        //动画组
        AnimationSet as = new AnimationSet(true);
        as.setDuration(3000);
        //透明度动画
        AlphaAnimation aa = new AlphaAnimation(0, 1);
        aa.setDuration(3000);
        as.addAnimation(aa);
        //平移动画
        TranslateAnimation ta = new TranslateAnimation(0, 100, 0, 200);
        ta.setDuration(3000);
        as.addAnimation(ta);
        //启动动画
        view.startAnimation(as);
    }
}

Android属性动画

由于Animation框架改变的只是显示效果,并不能相应事件, 因此,在Android3.0之后引入了属性动画框架(Animator);Animator框架中使用最多的是AnimatorSet和ObjectAnimator的配合。

ObjectAnimator是属性动画框架中的最重要的实行类,创建一个ObjectAnimator只需通过他的静态工厂类直接返回一个ObjectAnimator对象,参数包括一个对象和对象的属性,但属性必须有get和set函数。

ObjectAnimator animator = ObjectAnimator.ofFloat(
      view,
      "translationX",
      300);
animator.setDuration(300);
animator.start();

ObjectAnimator : 常用动画属性说明

  • translationX 和 translationY :这两个属性通常用来控制view的平移。
  • rotaion、rotationX、rotationY :这三个属性控制view对象围绕支点进行2D和3D旋转。
  • scaleX 和 scaleY :这两个属性控制view对象围绕它的支点进行2D缩放。
  • pivotX 和 privotY :这两个属性控制view对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下,该支点位置就是view对象的中心点。
  • x 和 y :这两个属性描述了view对象在它的容器中的最终位置,它是最初的做坐标和tranlationX 和 translationY值的累计和。
  • alpha : 表示view对象的alpha透明度,默认值是1(不透明),0代表完全透明(不可见)。

注:如果一个属性没有get、set方法,也通过包装类的方法给属性增加get、set方法来实现动画,代码如下:

>     private static class WrapperView {
        private View mTarget;
        public WrapperView(View target) {
            mTarget = target;
        }
        public int getWidth() {
            return mTarget.getLayoutParams().width;
        }
        public void setWidth(int width) {
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }
    }

通过以上代码,就给属性提供了set、get方法,使用时只需要操作包装类即可

> WrapperView wrapper = new WrapperView(view);
ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(3000).start();

类似视图动画的AnimationSet,属性动画如果对同个对象要定义多个属性,就要用刀PropertyValuesHolder来实现。

>  //同时操作多个属性动画
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3).setDuration(3000).start();

ValueAnimator在属性动画中占有非常重要的地位,他本身不提供任何动画效果,他更像一个数值产生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程。

> //ValueAnimator
ValueAnimator animator = ValueAnimator.ofFloat(0, 400);
animator.setTarget(view);
animator.setDuration(1000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
 @Override
 public void onAnimationUpdate(ValueAnimator animation) {
     Float value = (Float) animation.getAnimatedValue();
     //TODO use the value
     if (value < 200) {
         ObjectAnimator.ofFloat(view, "translationX", 200).setDuration(1000).start();
     } else {
         ObjectAnimator.ofFloat(view, "translationY", 200).setDuration(1000).start();
     }
 }
});

一个完整的动画具有Start、Repeat、End、Cancel四个过程,通过Android提供的API可以很方便的监听这四个事件

>         ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
       animator.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) {
           //动画重复时
           }
       });

对于一个对象同时作用多个属性动画,可以用PropertyValuesHolder实现,同样也可以用AnimatorSet实现,而且AnimatorSet同时也能实现更为精确的顺序控制。

>//使用AnimatorSet实现作用多个动画
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 300f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playTogether(animator1, animator2, animator3);
set.start();

AnimatorSet正是通过playTogether()、playSequentially()、animSet.play().with()、before、after()等方法来对多个动画的播放顺序做精确的控制的。

在Android3.0之后,google给view增加了animate方法来直接设置属性动画。代码如下

>//通过view的animate方法直接设置属性动画
        view.animate().alpha(0).y(300).setDuration(3000).withStartAction(new Runnable() {
            @Override
            public void run() {
                //动画开始时
            }
        }).withEndAction(new Runnable() {
            @Override
            public void run() {
                //动画结束时
            }
        }).start();
    }

Android布局动画

布局动画,是指作用在ViewGroup上的动画,当ViewGroup增加view时添加一个动画的过渡效果。
最简单的布局动画是在ViewGroup的XML中,使用以下代码来设置

android:animateLayoutChanges="true"

另外还可通过LayoutAnimationController类来自定义一个子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设置布局动画
ll.setLayoutAnimation(lac);

LayoutAnimationController的第一个参数是需要作用的动画,第二个参数是每个子view的显示时间,当delay时间不为0时可以设置子view显示的顺序

  • LayoutAnimationController.ORDER_NORMAL--正序
  • LayoutAnimationController.ORDER_RANDOM -- 随机
  • LayoutAnimationController.ORDER_REVERSE -- 反序

通过插值器,可以定义动画变换的速率,有点类似于物理中的加速度。主要作用是用来控制目标变量的变化值然后进行对应的操作。

自定义动画

创建自定义动画,通常情况下只需要覆盖父类的initialize方法来实现一些初始化工作,并且实现applyTransformation逻辑就可以了。

> public
class
CustomAnim extends Animation
{
   private int mCenterWidth;
   private int mCenterHeight;
   private Camera mCamera = new Camera();
   private float mRotateY = 0.0f;
   @Override
   public void initialize(int width, int height, int parentWidth, int parentHeight) {
       super.initialize(width, height, parentWidth, parentHeight);
       //设置默认时长
       setDuration(2000);
       //设置动画结束后保留状态
       setFillAfter(true);
       //设置默认插值器
       setInterpolator(new BounceInterpolator());
       mCenterHeight = height/2;
       mCenterWidth = width/2;
   }
   //暴漏一个接口给外界设置旋转角度
   public void setRotateY(float rotateY) {
       mRotateY = rotateY;
   }
   @Override
   protected void applyTransformation(float interpolatedTime, Transformation t) {
       //获得当前的矩阵对象
       final Matrix matrix = t.getMatrix();
       mCamera.save();
       //使用Camera设置旋转的角度
       mCamera.rotateY(mRotateY * interpolatedTime);
       //将旋转变化作用到matrix上
       mCamera.getMatrix(matrix);
       mCamera.restore();
       //通过pre方法设置矩阵作用前的偏移量来改变旋转中心
       matrix.preTranslate(mCenterWidth, mCenterHeight);
       matrix.postTranslate(-mCenterWidth, -mCenterHeight);
   }
}

在上面这个例子中用到了Camera,这里的Camera不是指手机中的相机,而是android.graphics.Camera中的Camera类,它封装了openGL的3D动画,从而可以非常方便的创建3D动画效果。使用的时候就是通过设置三个坐标轴(X、y、z)的旋转角度,从而实现3d动画的效果

>mCamera.save();
//使用Camera设置旋转的角度
mCamera.rotateY(mRotateY * interpolatedTime);
mCamera.rotateY(mRotateY * interpolatedTime);
mCamera.rotateZ(mRotateY * interpolatedTime);
//将旋转变化作用到matrix上
mCamera.getMatrix(matrix);
mCamera.restore();

SVG矢量动画

SVG : 可伸缩适量图形,于Bitmap(位图)相比,最明显的优点是放大不会失真。

使用<path>标签创建SVG,就像用指令的方式来控制一只画笔,例如移动画笔到某一坐标位置,画一条直线,画一条曲线等。常用<path>指令有以下几种:

  • 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 = quadraic Belzier curve(Q X, Y, ENDX, ENDY) : 二次贝塞尔曲线。
  • T = smooth quadratic Belzier curveto(T ENDX, ENDY) : 映射前面路径后的终点。
  • A = cliptical Arc(A RX, RY, XROTATION, FLAG1, FLAG2, x, y) : 弧线。
  • Z = closepath() : 关闭路径。

注:使用这些指令需注意以下几点

  • 坐标轴以(0, 0) 为中心,X轴水平向右, Y轴水平向下。
  • 所有指令大小写均可,大写表示绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系。
  • 指令和数据间的空格可以省略。
  • 同一指令出现多次可以只用一个。

Goggle在Android5.x中提供了VectorDrawable和AnimatedVectorDrawable两个API来帮助支持SVG,首先使用VectorDrawable来创建基于XML的SVG图形,再结合AnimatedVectorDrawable来实现动画效果。

上一篇下一篇

猜你喜欢

热点阅读