您的位置:首页 > 移动开发 > Android开发

《Android群英传》读书笔记(8)第七章:Android动画机制与使用技巧

2015-12-20 13:17 561 查看

1.视图动画

Android视图动画的分类:

透明度动画——AlphaAnimation
旋转动画——RotateAnimation
位移动画——TranslateAnimation
缩放动画——ScaleAnimation
动画集合——AnimationSet

视图动画的监听方式:
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {

}

@Override
public void onAnimationEnd(Animation animation) {

}

@Override
public void onAnimationRepeat(Animation animation) {

}
});
2.属性动画

视图动画Animation存在一定的局限性,动画改变的只是显示,并不能响应事件,因此属性动画Animator就应运而生。Animator中使用最多的就是AnimatorSet和ObjectAnimator,AnimatorSet用来组合ObjectAnimator,ObjectAnimator只控制一个对象的属性值,而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay);设置动画之间的间隙时间,调整帧率。最重要的是属性动画通过调用属性的set、get方法来真实地控制一个View的属性值,因此强大的属性动画基本可以实现所有的动画效果。
ObjectAnimator的使用方法:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0, 300);
animator.setDuration(3000);
animator.start();


需要注意的是,要操纵的对象的属性必须具有get和set方法,不然属性动画就无法起效。
属性动画常用的属性:

translationX和translationY
rotation、rotationX和rotationY
scaleX和scaleY
pivotX和pivotY
x和y
alpha

如果一个属性没有get和set方法,可以通过对操作对象进行包装来实现set、get方法:
public 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();
}
}


然后对包装后的对象应用动画:
ObjectAnimator.ofInt(wrapperView, "width",
wrapperView.getWidth(), wrapperView.getWidth() * 2).setDuration(3000).start();
PropertyValuesHolder
类似视图动画中的AnimationSet,PropertyValuesHolder可以针对同一个对象的多个属性同时应用多种动画下面是使用示例:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX",1f,0f);
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY",1f,0f);
ObjectAnimator.ofPropertyValuesHolder(view,p1,p2,p3).setDuration(3000).start();


ValueAnimator
ValueAnimator是属性动画的核心所在,它本身不提供任何效果,更像是一个数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程。ValueAnimator的使用方法如下,通常在AnimatorUpdateListener中监听数值的变换,从而完成动画的变换:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
//TODO use the value
}
});
属性动画的监听
通过AnimatorListener监听动画执行的全过程:
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) {

}
});
或者使用AnimatorListener的实现类AnimatorListenerAdapter:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {

}
});
AnimatorSet
AnimatorSet除了能实现PropertyValuesHolder的功能之外,还能实现更为精确的控制动画播放的顺序,AnimatorSet中有playTogether()、playSequentially()、animSet.play().with()、before()、after()等方法。
在XML中使用属性动画

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="translationX"
android:interpolator="@android:interpolator/accelerate_cubic"
android:valueFrom="0dp"
android:valueTo="100dp"
android:valueType="intType"
>

</objectAnimator>
然后在代码中进行加载:

ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.anim);


除了使用Animator.start()方法启动动画外,在Android3.0之后Google还为View增加了animate方法来启动属性动画,代码如下所示:
view.animate()
.setDuration(1000)
.alpha(0)
.y(300)
.withStartAction(new Runnable() {
@Override
public void run() {

}
}).withEndAction(new Runnable() {
@Override
public void run() {

}
}).start();
3.Android布局动画

布局动画是指作用在ViewGroup上,给ViewGroup添加View时的一个动画过渡效果,在ViewGroup的布局XML中通过android:animateLayoutChanges="true"来打开布局动画,然后有新view加入时就会显示默认的布局动画效果了。
另外还可以通过LayoutAnimationController类来自定义一个子view的过渡效果:
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
sa.setDuration(500);
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
ll.setLayoutAnimation(lac);
LayoutAnimationController构造方法的第一个参数是需要作用的动画,第二个参数是每个子view显示的间隔时间。当间隔不为0时可以为子view设置显示顺序:

LayoutAnimationController.ORDER_NORMAL

LayoutAnimationController.ORDER_RANDOM

LayoutAnimationController.ORDER_REVERSE

4.自定义动画
创建自定义动画需要继承自Animation类,然后重写applyTransformation方法就可以了,有时还要重写initialize()方法来完成一些初始化的工作。applyTransformation方法有以下几个参数:
applyTransformation(float interpolatedTime,Transformation t);
interpolatedTime这个值就是插值器(Interpolator)的时间因子,这个值有当前动画完成的百分比和当前时间对应的插值计算得来,范围是0到1.0,第二个参数Transformation是矩阵的封装类,一般用它来获取当前的矩阵对象:
final Matrix matrix = t.getMatrix();
通过改变matrix来实现动画效果,下面代码实现了模拟电视机关闭屏幕的动画效果:
public class CustomAnimation extends Animation {
private int mCenterWidth;
private int mCenterHeight;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCenterWidth = width / 2;
mCenterHeight = height / 2;
}

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

}
}
结合android.graphics.Camera类还可以实现3D的切换效果,下面是一个3D的旋转动画的代码:

public class CustomAnimation extends Animation {
private int mCenterWidth;
private int mCenterHeight;
private Camera mCamera;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCenterWidth = width / 2;
mCenterHeight = height / 2;
mCamera = new Camera();
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
final Matrix matrix = t.getMatrix();
mCamera.save();
mCamera.rotateY(interpolatedTime * 360);
mCamera.getMatrix(matrix);
mCamera.restore();
matrix.preTranslate(-mCenterWidth, -mCenterHeight);
matrix.postTranslate(mCenterWidth, mCenterHeight);

}
}

5.SVG矢量动画

在Android5.0开始,增加了矢量图形的支持,来看一下什么是SVG

可伸缩矢量图形(Scalable Vector Graphics)
使用XML格式定义图形
图像在放大或改变尺寸的情况下其图形质量不会损失
万维网联盟标准
与诸如DOM和XSL之类的W3C标准是一个整体。

path标签指令:

M = moveto(M X,Y)——将画笔移动到指定的坐标位置
H = horizontal lineto(L X,Y)——画直线到指定的坐标位置
V = vertical lineto(V,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 curve(T ENDX,ENDY)——映射前面路径后的终点
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y)——弧线

Z = closepath()——关闭路径

在使用以上命令时要注意:

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

下面来看SVG常用命令的使用方法:

L

绘制直线的指令是L,L之后的参数是一个坐标如“L 200,400”还可以使用H和V来绘制水平和竖直线

M

M类似绘图中的path类的moveTo方法,即代表将画笔移动到某一点,并不发生绘制动作

A

A指令用来绘制一段弧线,且允许弧线不闭合。可以把A命令绘制的弧线想象成是椭圆的某一段,A指令有以下几个参数:

RX,RY指所在椭圆的半轴大小
XROTATION指椭圆的X轴与水平方向顺时针夹角,可以想象成一个水平的椭圆绕中心点顺时针旋转XROTATION的角度。
FLAG1只有两个值,1表示大角度弧线,0表示小角度弧线
FLAG2只有两个值,确定从起点到终点的方向,1为顺时针,0为逆时针。
X,Y为终点坐标

Android中使用SVG
Android中提供了VectorDrawable和AnimatedVectorDrawable来支持SVG。
VectorDrawable用于创建基于XML的SVG图形,并结合AnimatedVectorDrawable来实现动画效果。
下面是VectorDrawable的使用示例:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="100dp"
android:viewportHeight="100"
android:viewportWidth="100"
>
<group
android:name="test"
android:rotation="0"
android:pivotX="50"
android:pivotY="50"
>
<path
android:strokeColor="@android:color/holo_orange_dark"
android:strokeWidth="2"
android:pathData="
M 25,50
a 25,25 0 1,0 50,0"
>

</path>
</group>

</vector>


其中的fillColor属性用来绘制填充的图形,绘制非填充的图形使用strokeColor结合strokeWidth来实现。

AnimatedVectorDrawable的作用是给VectorDrawable提供动画效果,它将VectorDrawable和属性动画进行结合,就可以实现具有动画效果的Vector了。
下面是AnimatedVectorDrawable使用示例:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_drawable"
>
<target
android:animation="@animator/anim"
android:name="test"/>

</animated-vector>
其中的animation属性指向的是属性动画Animator。来看一下这个动画:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:propertyName="rotation"
android:interpolator="@android:interpolator/accelerate_cubic"
android:valueFrom="0"
android:valueTo="360"
>

</objectAnimator>

AnimatedVectorDrawable创建好后,可以通过给ImageView等空间设置src属性进行设置然后在代码中通过((Animatable)imageView.getDrawable()).start();来开启动画。

线图动画

通过将属性动画的propertyName属性设置为pathData,就可以根据VectorDrawable的pathData属性来进行动画了。下面是使用示例,展示里两条平行线变换成叉的动画,

这是VectorDrawable文件:

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

</vector>
属性动画文件,只列出了其中的一个,两个动画类似:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="pathData"
android:duration="500"
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/accelerate_interpolator"
>
</objectAnimator>
AnimatedDrawable文件:

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_cross"
>
<target
android:animation="@animator/anim_path1"
android:name="path1"/>
<target
android:animation="@animator/anim_path2"
android:name="path2"/>
</animated-vector>


需要注意的是当属性动画的propertyName指定为pathData时,valueType属性也要指定为pathType的类型。

下面是一个搜索框的动画效果:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="60dp"
android:width="320dp"
android:viewportHeight="30"
android:viewportWidth="160"
>
<group>
<path android:name="search"
android:strokeWidth="1.5"
android:strokeAlpha="0.0"
android:strokeColor="#ff3570be"
android:strokeLineCap="round"
android:pathData="
M141,17
A9,9 0 1,1 142,16
L149,23"
/>
<path android:name="bar"
android:strokeWidth="1.5"
android:strokeAlpha="0.8"
android:strokeColor="#ff3570be"
android:strokeLineCap="square"
android:pathData="
M0,23
L149,23"
/>
</group>

</vector>


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

</objectAnimator>
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_search">
<target
android:animation="@animator/anim_search"
android:name="search"/>
<target
android:animation="@animator/anim_alpha"
android:name="search"/>
</animated-vector>



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: