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();`