《Android群英传》---读书笔记5

标签: android中级 读书笔记


Android动画机制与使用技巧

包括:
Android视图动画
Android属性动画
还包括下一篇的 Android5.X引入的 SVG 矢量动画

7.1 Android View动画框架

Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View
视图动画使用很简单,提供了AlphaAnimation,RotateAnimation,TranslateAnimation,ScaleAnimation四种动画方式,并且提供了AnimationSet动画集合,混合使用多种动画
可以使用XML文件来描述一个动画过程,同样也可以使用代码来控制整个动画过程

透明度动画
AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
view.starAnimation(aa);

旋转动画
RotateAnimation ra=new RotateAnimation(0,360,100,100);
ra.setDuration(1000);
view.startAnimation(ra);
也可以将旋转中心设置为自身中心点
RotateAnimation ra=new RotateAnimation(0,360,RorateAnimation,RELATIVE_TO_SELF,0.5F,RELATIVE_TO_SELF,0.5F);

位移动画
TranslateAnimation ta=new TranslateAnimation(0,200,0,300);
ta.setDuration(1000);
view.startAnimation(ta);

缩放动画
ScaleAnimation sa=new ScaleAnimation(0,2,0,2);
sa.setDuration(1000);
view.startAnimation(sa);
也可以设置旋转中心为自身中心

动画集合
AnimationSet as=new AnimationSet(true);
as.setDuration(1000);

AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
as.addAnimation(aa);

TranslateAnimation ta=new TranslateAnimation(0,100,0,200);
ta.setDuration(1000);
as.addAnimation(ta);

view.startAnimation(as);

对于动画事件,可以设置对应的监听回调
animation.setAnimationListener(new Animation.AnimationListener(){
@Override
public void onAnimationStart(Animation animation){
}
@Override
public void onAnimationEnd(Animation animation){
}
@Override
public void onAnimationRepeat(Animation animation){
}
});

7.2 Android属性动画分析

Animation(即视图动画)存在的一些局限性—例如改变的只是显示,不能相应事件,所以引入了属性动画
Animator框架中使用最多就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更加精细化的控制。而且可以调用setFrameDelay(longframDelay)设置动画帧之间的间隙时间,减少CPU资源的消耗。

7.2.1 ObjectAnimator
使用ObjectAnimator控制的对象的相应属性,该属性必须具有get和set函数。
ObjectAnimator animator =ObjectAnimator.ofFloat(view,”translationX”,300);
animator.setDuration(300);
animator.start();

常用的属性动画的属性值:
translateX和translationY:控制着View对象从它布局容器的左上角坐标的偏移量
rotation,rotationX和rotationY:控制View对象围绕支点进行2D和3D旋转
scaleX和scaleY:围绕支点进行2D缩放
pivotX和pivotY:控制View对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下就是View对象的中心点
x和y:描述了View对象在它的容器中的最终位置,它是translationX,translationY值得累计和
alpha:表示View对象的alpha透明度

如果一个属性没有get,set方法,可以采用包装类的方式,或者使用ValueAnimator来实现

private static WrapperView{
private View mTarget;
public WrapperView(View target){
    mTarget=target;
}
public int getWidth(){
return mTarget.getLayoutParams().width;
}
public void setWidth(){
    mTarget.getLayoutParams().width=width;
    mTarget.requestLayout();
}
}
然后 就可以通过包装类来间接使用ObjectAnimator来使用属性动画
ViewWrapper wrapper=new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();

7.2.2 PropertyValuesHolder
类似于视图动画中的AnimationSet,在属性动画中,可以使用PropertyValuesHolder来实现对同一个对象的多个属性,同时作用多种动画。例如在平移动画中,在平移的过程中同时改变X,Y轴的缩放

PropertyValuesHolder phv1=PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder phv2=PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuseHolder.ofFloat("scaleY",1f,0,1f);
ObjectAnimator.ofPropertyValuesHolder(view,phv1,phv2,phv3).setDuration(1000).start();

7.2.3 ValueAnimator
ValueAnimator本身不提供任何动画效果,它更像一个数值发生器,用来产生具有一定规律的数值从而让调用者来控制动画的实现过程

ValueAnimator animator=ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(3000).start();
animator.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimatorUpdate(ValueAnimator animation){
Float value=(Float)animation.getAnimatedValue();
//TODO use the value
}
});

7.2.4 动画事件的监听
一个完整的动画具有 Start, Repeat,End,Cancel四个过程,

ObjectAnimator anim=ObjectAnimator.ofFloat(view,"alpha",0.5f);
anim.addListener(new AnimatorListener(){
//some Methods to Override...
});

不过大多数时候我们只关心onAnimationEnd事件,所以只需要通过AnimatorListenerAdapter进行监听就行

anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){

}
});

7.2.5 AnimatorSet
AnimatorSet相比PropertyValuesHolder能实现更加精确的控制

ObejectAnimator animator1=ObjectAnimator.ofFloat(view,"translationX",300f);
ObejectAnimator animator2=ObjectAnimator.ofFloat(view,"scaleX",1f,0f,1f);
ObejectAnimator 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()这些方法来控制多个动画的协同工作方式

7.2.6 在XML中使用属性动画

<?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>

然后直接在程序中使用
public void scaleX(View view){
Animator anim=Animator.loadAnimator(this,R.animator.scalex);
anim.setTarget(mMv);
anim.start();
}

7.2.7 View的animate方法
Android 3.0之后,可以使用View的animate方法直接驱动属性动画

view.animate().alpha(0).y(300).setDuration(300).withStartAction(new Runable(){
@Override
public void run(){  }
}).withEndAction(new Runable(){
@Override
 public void run(){ 
    runOnUiThread(new Runable(){
        @Override
         public void run(){  }
         }
    });
    }
}).start();

7.3 Android布局动画

布局动画就是指ViewGroup增加View时添加一个动画过度效果。
最简单的布局动画就是在ViewGroup的XML中,使用以下代码来打开布局动画,从而实现默认的动画效果
android:animateLayoutChanges=”true”

另外还可以使用LayoutAnimationController类来自定义一个子View的过度效果

LinerLayout ll=(LinearLayout)findViewById(R.id.ll);
//设置过度动画
ScaleAnimation sa=new ScaleAnimation(0,1,0,1);
sa.setDuration(2000);
//设置布局动画的显示属性
LayoutAnimatorController lac=new LayoutAnimationController(sa,0.5f);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
//为ViewGroup设置布局动画
ll.setLayoutAnimation(lac);

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

Interpolators(插值器)

通过插值器可以定义动画的变换速率,非常类似于物理中的加速度,其主要作用是控制目标变量的变化值进行对应的变化。在不同的插值器的作用下同一个动画的起始值,每个单位时间内所达到的变化值是不一样的。

7.5 自定义动画、

创建自定义动画非常简单,只需要实现它的applyTransformation的逻辑就可以了,不过通常情况下,还需要覆盖父类的initialize方法来进行一些初始化工作。

applyTransformation(float interpolateTime,Transformation t)//第一个参数为时间因子,取值范围0到1.0;第二个参数为一个矩阵的封装类,一般通过这个类来获得当前的矩阵对象:final Matrix matrix=t.getMatrix();
通过改变获得的matrix对象,就可以将动画效果实现出来

下面的代码示例实现一个类似于电视机关闭的动画

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class CustomTV 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(1000);
    // 动画结束后保留状态
    setFillAfter(true);
    // 设置默认插值器
    setInterpolator(new AccelerateInterpolator());
    mCenterWidth = width / 2;
    mCenterHeight = height / 2;
}

// 暴露接口-设置旋转角度
public void setRotateY(float rorateY) {
    mRotateY = rorateY;
}

@Override
protected void applyTransformation(
        float interpolatedTime,
        Transformation t) {
    final Matrix matrix = t.getMatrix();
    matrix.preScale(1,
            1 - interpolatedTime,
            mCenterWidth,
            mCenterHeight);
}
}

也可以结合矩阵,并使用Camera类来实现一个自定义的3D动画。
这里的Camera类指的是android.graphics.Camera中的Camera类,它封装课openGL的3D动画,从而可以非常方便的创建3D动画效果

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.Transformation;

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());
    mCenterWidth = width / 2;
    mCenterHeight = height / 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);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值