Android群英传读书笔记(第七章)
本章主要介绍的是Android动画机制和使用技巧
# 1.Android视图动画分析
## 透明度动画:
~~~
AlphaAnimation aa=new AlphaAnimation(0,1);
aa.setDuration(1000);
view.startAnimation(aa);
~~~
## 旋转动画:
~~~
RotateAnimation ra=new RotateAnimation(0,360,100,100);//参数分别为起始角度,旋转到角度,中心xy坐标
ra.setDuration(1000);
view.startAnimation(ra);
~~~
也可以绕自身中心旋转:
~~~
RotateAnimation ra=new RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
ra.setDuration(1000);
view.startAnimation(ra);
~~~
## 位移动画:
~~~
TranslateAnimation ta=new TranslateAnimation(0,300,0,200);
ta.setDuration(1000);
view.startAnimation(ta);
~~~
## 缩放动画:
~~~
ScaleAnimation sa=new ScaleAnimation(0,2,0,2);
sa.setDuration(1000);
view.startAnimation(sa);
~~~
和旋转动画一样,缩放也能以中心点进行:
~~~
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
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);
~~~
## 动画回调:
~~~
as.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始时回调
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束时回调
}
@Override
public void onAnimationRepeat(Animation animation) {
//重复时回调
}
});
~~~
* 总结:视图动画的效果比较局限,并且view本身是不会跟着平移动画移动的,只有在实现简单效果并且不需和用户发生交互时建议使用。
# 2.Android属性动画分析
属性动画是在3.0以后推出的,如果需兼容之前的版本需使用开源项目:NineOldAndroids(可以通过谷歌查询其用法,此处不做介绍)
属性动画通过调用属性的set、get方法来真实的控制一个View的属性,还可以调用setFrameDelay()设置动画帧之间的间隙时间,减少动画过程中频繁绘制界面。
##
* ObjectAnimator:
~~~
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(view,"translationX",300);
objectAnimator.setDuration(1000);
objectAnimator.start();//属性动画的简单使用。
~~~
下面是些常用的属性:
* translationX和translationY:作为一种增量来控制着View对象从它布局容器左上角坐标的偏移位置。
* rotation、rotationX和rotationY:这三个属性控制View对象围绕支点进行2D和3D的旋转。
* scaleX和scaleY:这两个属性控制着View对象围绕它的支点进行2D缩放。
* pivotX和pivotY:这两个属性控制着View对象的支点位置,围绕这个支点进行旋转缩放,默认情况下是View的中心点。
* x和y:它描述了View对象在它容器中的最终位置,它是最初的左上角坐标的translationX和translationY值的累积和。
* alpha:它表示View对象的透明度,1是不透明,0为全透明。
如果一个属性没有get、set方法时就需要用其他解决方案了,Google提供了两种方法来解决这个问题。
①通过一个自定义类来间接的提供这个属性的get、set方法:
~~~
private static class WrapperView{
//使用时就new一个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();
}
}
~~~
②使用ValueAnimator来实现:本文后面会介绍。
## PropertyValuesHolder:
类似于视图动画中的AnimationSet。这里直接上代码
~~~
PropertyValuesHolder holder0 = PropertyValuesHolder.ofFloat("translationX", 300);
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("translationY", 300);
ObjectAnimator.ofPropertyValuesHolder(view, holder0, holder1, holder2).setDuration(1000);
~~~
## ValueAnimator:
ObjectAnimator继承自ValueAnimator。其本身不提供任何动画效果,它更像是一个数值发生器。
~~~
ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,100);
valueAnimator.setTarget(view);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//监听数值的变换,从而完成动画的变换
Float value= (Float) animation.getAnimatedValue();
}
});
~~~
## 动画事件的监听:
~~~
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
objectAnimator.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) {
//动画重复
}
});
//大部分时候只需要监听结束事件,因此可以选择AnimatorListenerAdapter。
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
objectAnimator.start();
~~~
## AnimatorSet:
AnimatorSet不仅可以实现PropertyValuesHolder这样的效果(同时执行多个动画操作),它还能实现更为精确的顺序控制。(注意这里是AnimatorSet,而不是AnimationSet)
~~~
ObjectAnimator objectAnimator0=ObjectAnimator.ofFloat(view,"scaleX",1f,0,1f);
ObjectAnimator objectAnimator1=ObjectAnimator.ofFloat(view,"scaleY",1f,0,1f);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.playTogether(objectAnimator0,objectAnimator1);
set.start();
~~~
控制顺序有以下方法:
* playTogether():一起执行。
* playSequentially():上个动画结束后下个才会执行。
* animSet.play(anim0).with(anim1):anim0和anim1一起执行。
* animSet.play(anim0).before(anim1):anim0在anim1之前执行。
* animSet.play(anim0).after(anim1):anim0在anim1之后执行。
## 在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"
android:valueTo="0.5">
</objectAnimator>
~~~
在代码中的使用:
~~~
Animator animator= AnimatorInflater.loadAnimator(getContext(),R.anim.test);
animator.setTarget(view);
animator.start();
~~~
View的animate方法:
在3.0后,google公司给View增加了animate方法来直接驱动属性动画,代码如下:
~~~
//withStartAction和withEndAction在api16以上才有。
view.animate().alpha(0).y(300).setDuration(1900).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" //此为固定默认效果`
当然我们也能够通过LayoutAnimationController类来自定义一个子View的过渡效果。
~~~
LinearLayout ll=new LinearLayout(getContext());
//创建动画
ScaleAnimation sa=new ScaleAnimation(0,1,0,1);
sa.setDuration(1000);
//设置布局动画的显示属性
//第二个参数是每个子View显示的delay时间。当delay不为0时可以设置子View显示顺序
//LayoutAnimationController.ORDER_NORMAL 顺序
//LayoutAnimationController.ORDER_RANDOM 随机
//LayoutAnimationController.ORDER_REVERSE 反序
LayoutAnimationController controller=new LayoutAnimationController(sa,0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
ll.setLayoutAnimation(controller);
~~~
# 4.Interpolators(插值器)
通过插值器,可以定义动画变换的速率,类似于物理中的加速度。
* AccelerateDecelerateInterpolator --- 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
* AccelerateInterpolator --- 在动画开始的地方速率改变比较慢,然后开始加速
* AnticipateInterpolator --- 开始的时候向后然后向前甩
* AnticipateOvershootInterpolator --- 开始的时候向后然后向前甩一定值后返回最后的值
* BounceInterpolator --- 动画结束的时候弹起
* CycleInterpolator --- 动画循环播放特定的次数,速率改变沿着正弦曲线
* DecelerateInterpolator --- 在动画开始的地方快然后慢
* LinearInterpolator --- 以常量速率改变
* OvershootInterpolator --- 向前甩一定值后再回到原来位置
以上基本能满足常用需求,也可以自定义一个插值器。
~~~
public class MyInterpolator implements Interpolator {
private float mFactor;
@Override
public float getInterpolation(float input) {
//通过操作input来改变速率
return mFactor;
}
}
~~~
# 5.自定义动画
创建自定义动画非常简单,只需要实现它的applyTransformation的逻辑,通常情况下还需要覆盖父类的initialize方法来实现一些初始化工作。
~~~
public class MyAnim extends Animation {
private int mWidth;
private int mHeight;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mWidth = width;
mHeight = height;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
//这个方法主要就是通过操作transformation中的矩阵对象来呈现动画效果
final Matrix matrix = t.getMatrix();
matrix.preScale(1, 1 - interpolatedTime, mWidth / 2, mHeight / 2);
}
}
~~~
# 6.Android 5.X SVG矢量动画机制
* SVG是什么:
* 可伸缩矢量图形(Scalable Vector Graphics)
* 定义用于网络的基于矢量的图形
* 使用xml格式定义图形
* 图像在放大或者改变尺寸的情况下其图形质量不会有损失
* 万维网联盟的标准
* 与诸如DOM和XSL之类的W3C标准是一个整体
* <path>标签:
使用<path>标签创建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):弧形。RX、RY为半轴大小,XROTATION指椭圆的X轴水平方向顺时针方向夹角,FLAG1为1时表示大角度弧形,为0表小角度,FLAG2为1时表顺时针,0位逆时针,X、Y为终点坐标
* Z=closepath():关闭路径。
注意:
① 坐标轴以(0,0)为中心,X轴水平向右,Y轴水平向下。
② 所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系。
③ 指令和数据间的空格可以省略。
④ 同一指令出现多次可以只用一个。
* SVG编辑器:
书中介绍了个Inkscape,有兴趣的可以尝试下。
* Android中使用SVG:
谷歌在Android 5.X中提供了VectorDrawable、AnimatedVectorDrawable来帮助支出SVG。
VectorDrawable:
~~~
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"//控制SVG图形的具体大小,height与width的比例需和viewportHeight与viewportWidth的相同,不然会变形
android:viewportHeight="100"
android:viewportWidth="100">//图形划分的比例,这里指划分100*100,绘制图形使用坐标(50,50)即为中心点
<group
android:name="test"
android:rotation="0">
<path
android:fillColor="@android:color/holo_blue_light"
android:pathData="M 25 50
a 25 25 0 1 1 50 0"
/>
</group>
</vector>
~~~
* AnimatedVectorDrawable:
AnimatedVectorDrawable就是给VectorDrawable提供动画效果,通过它来连接静态的VectorDrawable和动态的objectAnimator。
~~~
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_demo">
<target
android:animation="@anim/anim"
android:name="test"/>//这里的name需要和vectordrawable里的name一样
</animated-vector>
~~~
动画代码如下:
~~~
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="rotation"//path中的属性
android:valueFrom="0"
android:valueTo="360">
</objectAnimator>
~~~
具体使用如下:
`((Animatable)imageView.getDrawable()).start();`