第七章目錄
- 7.1 Android View動畫架構
- 7.1.1 透明度動畫
- 7.1.2 旋轉動畫
- 7.1.3 位移動畫
- 7.1.4 縮放動畫
- 7.1.5 動畫集合
- 7.2 Android屬性動畫分析
- 7.2.1 ObjectAnimator
- 7.2.2 PropertyValuesHolder
- 7.2.3 ValueAnimator
- 7.2.4 動畫事件的監聽
- 7.2.5 AnimatorSet
- 7.2.6 在XML中使用屬性動畫
- 7.2.7 View的animate方法
- 7.3 Android布局動畫
- 7.4 Interpolators
- 7.5 自定義動畫
- 7.6 Android5.X SVG矢量動畫機制
- 7.6.1 <path>标簽
- 7.6.2 SVG常用指令
- 7.6.3 SVG編輯器
- 7.6.4 Android中使用SVG
- 7.6.5 SVG動畫執行個體
- 7.7 Android動畫特效
- 7.7.1 靈動菜單
- 7.7.2 計時器動畫
- 7.7.3 下拉展開動畫
第七章讀書筆記
動畫分為視圖動畫和屬性動畫
7.1 Android View動畫架構
7.1.1 透明度動畫
- View動畫定義了透明度、旋轉、縮放、位移幾種常見的動畫
- 實作原理:每次繪制視圖時View所在的ViewGroup中的drawChild函數擷取該View的Animation的Transformation值,然後調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀
- View動畫使用簡單,效率高,但是不具備互動性
7.1.2 旋轉動畫AlphaAnimation aa = new AlphaAnimation(0,1); aa.setDuration(1000); view.startAnimation(aa);
RotateAnimation ra = new RotateAnimation(0,360,100,100); ra.setDuration(1000); view.startAnimation(ra);
- 參數分别為旋轉起始角度和中心點的坐标,以自身中心點設定旋轉動畫:
7.1.3 位移動畫RotateAnimation ra = new RotateAnimation(0,360, RotateAnimation.RELATIVE_TO_SELF,0.5F, RotateAnimation.RELATIVE_TO_SELF,0.5F);
7.1.4 縮放動畫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);
- 以自身中心點設定縮放動畫:
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);
7.1.5 動畫集合
通過AnimationSet,将動畫以組合的形式展現出來:
系統還提供了對應的監聽回調,可以得到動畫的開始,結束和重複事件: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,200,0,300); 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屬性動畫分析
7.2.1 ObjectAnimator
- Animator架構中使用最多的就是AnimatorSet和ObjectAnimator
- 屬性動畫通過調用屬性的get、set方法來真實地控制了一個View的屬性值
簡單的平移動畫的實作:
- 隻需通過靜态工廠直接傳回一個ObjectAnimator對象
- 參數包括一個對象和對象的屬性,這個屬性必須有get和set函數
- 調用setInterpolator來設定相應的插值器
- 舊版本的視圖動畫隻是改變了顯示,沒有改變事件響應的位置
參數介紹:ObjectAnimator animator = ObjectAnimator.ofFloat(view,"translationX",300); animator.setDuration(300); animator.start();
一些常用的可以直接使用的屬性:
- 被操作的View
- 要操作的屬性,屬性必須有get、set方法,要不無法使用
- 可變數組,傳遞該屬性變化的一個取值過程
如果某個屬性沒有get、set方法,兩種方案來解決:
- translationX和translationY:作為一種增量來控制着View對象從它布局容器的左上角坐标偏移的位置
- rotation、rotationX和rotationY:控制View對象圍繞支點進行2D和3D旋轉
- scaleX和scaleY:控制View對象圍繞它的支點進行2D縮放
- pivotX和pivotY:控制View對象的支點位置,圍繞這個支點進行旋轉和縮放變換處理,預設情況下,該支點的位置就是View對象的中心點
- x和y:它描述了View對象在它的容器中的最終位置,它是最初的左上角坐标和 translationX和 translationY值的累計和
- alpha:它表示View對象的alpha透明度,預設值是1(不透明),0代表完全透明(不可見)
以自定義一個屬性增加get、set方法為例:
- 自定義一個屬性或者包裝類
- 通過ValueAnimator實作
通過代碼使用: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(); } }
7.2.2 PropertyValuesHolderWrapperView wrapper = new WrapperView(mButton); ObjectAnimator.ofInt(wrapper ,"width",500).setDuration(5000).start();
- 類似視圖動畫的AnimationSet,可以實作多個屬性動畫的組合
- 在平移的過程中,同時改變X、Y軸的縮放,可以這樣實作:
7.2.3 ValueAnimatorPropertyValuesHolder 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(1000).start();
- ObjectAnimator繼承自ValueAnimator
- ValueAnimator本身不提供任何動畫效果,它更像一個數值發生器,用來産生具有一定規律的數字,進而讓調用者來控制動畫的實作過程,通過AnimatorUpdateListener監聽數值的變換:
ValueAnimator animator = ValueAnimator.ofFloat(0,100); 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 } });
7.2.4 動畫事件的監聽
系統提供了屬性動畫的監聽回調:
大部分我們隻關心End事件,是以Android也提供了一個AnimatorListenerAdapter來讓我們選擇必要的事件監聽:ObjectAnimator anim = ObjectAnimator.ofFloat(view,"alpha",0.5f); anim.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) { } });
7.2.5 AnimatorSetanim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } });
- AnimatorSet可以實作和PropertyValuesHolder一樣的效果,不同的是Animator還可以實作更精确的順序控制:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 300f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0, 1f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0, 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檔案中編寫:
在程式中使用也簡單:<?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>
private void scaleX(View view){ Animator anim = AnimatorInflater.loadAnimator(this,R.animator.scaleX); anim.setTarget(mMv); anim.start(); }
7.2.7 View的animate方法
Google給View增加了animate方法來直接驅動屬性動畫:
animate.animate().alpha(0).y(300).setDuration(300).withStartAction(new Runnable() { @Override public void run() { } }).withEndAction(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { } }); } }).start();
7.3 Android布局動畫
- 布局動畫的作用是指ViewGroup添加view的時候添加一個動畫過濾效果
- 最簡單的布局動畫就是在ViewGroup的XML中打開一個系統預設的效果:
android:animateLayoutChanges="true"
還可以通過LayoutAnimationController實作自定義子view的過渡效果
LayoutAnimationController 第一個參數是需要的動畫,第二個參數是每個子View顯示的delay時間,若時間不為0,還可以setOrder設定子View的顯示順序:
- LayoutAnimationController.ORDER_NORMAL:順序
- LayoutAnimationController.ORDER_RANDOM:随機
- LayoutAnimationController.ORDER_REVEESE:反序
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);
7.4 Interpolators(插值器)
- 插值器是可以控制動畫變換速率的一個屬性值,是勻速的還是先快後慢還是先慢後快還是反彈等等好多種插值器
- 這裡就不介紹了,好多種直接用就好
7.5 自定義動畫
模拟電視關閉效果:
- 需要實作它的applyTransformation的邏輯
- 需要覆寫父類的initalize方法實作一些初始化工作
android.graphics.Camera中的Camera類,它封裝了openGL的3D動畫,進而可以風場友善地建立3D動畫效果,隻要移動Camera就能拍攝到具有立體感的圖像:@Override protected void applyTransformation(float interpolatedTime, Transformation t) { final Matrix matrix = t.getMatrix(); // 縮放以及縮放的中心點 matrix.preScale(1, 1 - interpolatedTime, mCenterwidth,mCenterheight); super.applyTransformation(interpolatedTime, t); }
@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; } @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); }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結
7.6 Android 5.X SVG 矢量動畫機制
SVG的定義:Android5.X之後添加了對SVG的<path>标簽的支援,其優點是:
- 可伸縮矢量圖形(Scalable Vector Graphics)
- 定義用于網絡的基于矢量的圖形
- 使用XML格式定義圖形
- 圖檔在放大或改變尺寸的情況下其圖形品質不會有所損失
- 網際網路聯盟的标準
- 與諸多DOM和XSL之類的W3C标準是一個整體
- 放大不會失真
- bitmap需要為不同分辨率設計多套圖示,而矢量圖則不需要
7.6.1 <path> 标簽
使用<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 = quadratic Belzier curve(Q X Y,ENDX,ENDY):二次貝塞爾曲線
- T = smooth quadratic Belzier curvrto(T,ENDX,ENDY):映射前面路徑的終點
- A = elliptical Are(A RX,RY,XROTATION,FLAG1FLAG2,X,Y):弧線
- Z = closepath():關閉路徑
7.6.2 SVG常用指令
- 坐标軸以(0,0)為中心,X軸水準向右,Y軸水準向下
- 所有指令大小寫均可,大寫絕對定位,參照全局坐标系,小寫相對定位,參照父容器坐标系
- 指令和資料間的空格可以無視
- 同一指令出現多次可以隻用一個
7.6.3 SVG編輯器
L
繪制直線的指令是“L”,代表從目前點繪制直線到給定點,“L”之後的參數是一個點坐标,同時,還可以使用“H”和“V”指令來繪制水準、豎直線,後面的參數是x坐标或y坐标
M
M指令類似Android繪圖中的path類moveto方法,即代表畫筆移動到某一點,但并不發生繪圖動作
A
A指令是用來繪制一條弧線,且允許弧線不閉合,可以把A指令繪制的弧度想象成橢圓的某一段,A指令一下有七個參數
- RX,RY:所在的橢圓的半軸大小
- XROTATION:橢圓的X軸與水準方向順時針方向的夾角,可以想象成一個水準的橢圓饒中心點順時針旋轉XROTATION 的角度
- FLAG1:隻有兩個值,1表示大角度弧度,0為小角度弧度
- FLAG2:隻有兩個值,确定從起點到終點的方向1順時針,0逆時針
- X,Y軸:終點坐标
- 線上可視化SVG編輯器官網:http://editor.method.ac/
- 優秀的離線SVG編輯器:Inkscape
7.6.4 Android 中使用SVG
Android5.X提供了兩個API來支援SVG:
- VectorDrawable:在XML中可以建立一個靜态的SVG圖形
- AnimatedVectorDrawable:給VectorDrawable提供動畫效果
7.6.4.1 VectorDrawable
VectorDrawable的使用是通過<vector>标簽來聲明的:
如果做過Web的應該對viewport應該很熟悉<?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="100dp" android:viewportWidth="100dp"> </vector>
接下來,給<vector>标簽增加顯示path:
- height:表示SVG的高度200dp
- width:表示SVG的寬度200dp
- viewportHeight:表示SVG圖形被劃分成100份
- viewportWidth:表示SVG圖形被劃分成100份
- 如果在繪圖中使用坐标(50,50),則意味着該坐标為正中間
布局檔案中這樣用:<?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="100dp" android:viewportWidth="100dp"> <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,0 50,0" /> </group> </vector>
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/vector" />
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 7.6.4.2 AnimatedVectorDrawable![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 1、首先在XML檔案中通過<animated-vector>标簽來聲明對AnimatedVectorDrawable的使用:
- AnimatedVectorDrawable使用:Google工程師将其比喻為一個膠水,通過其連接配接靜态的VectorDrawable和動态的objectAnimator
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector"> <target android:name="test" android:animation="@anim/anim_earth" /> </animated-vector>
特别注意的是:這個target裡面的name要和VectorDrawable的name對應,animation要和動畫資源檔案對應
2、對應的VectorDrawable檔案:
3、4、對應的animation檔案:<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="200dp" android:height="200dp" android:viewportHeight="100" android:viewportWidth="100"> <group android:name="test" android:rotation="0"> <path android:pathData=" M 25 50 a 25,25 0 1,0 50,0" android:strokeColor="@android:color/holo_blue_light" android:strokeWidth="2" /> </group> </vector>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" />
特别注意的是:在<group>标簽和<path>标簽中添加了rotate、fillColor、pathData等屬性,那麼可以通過objectAnimator指定android:propertyName=”XXXX”屬性來控制哪一種屬性,如果指定屬性為pathData,那麼需要添加一個屬性——android:valueType=”pathType”來告訴系統進行pathData的變換
4、在布局檔案中使用:
5、在Activity中開啟動畫:<ImageView android:id="@+id/image" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/anim_vector" />
ImageView image = (ImageView) findViewById(R.id.image); ((Animatable)image.getDrawable()).start();
7.6.5 SVG動畫執行個體
7.6.5.1 線圖動畫
1、定義我們的VectorDrawable
2、定義兩個Path的objectAnimator,從path1到path2<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:pathData=" M 20,80 L 50,80 80,80" android:strokeColor="@android:color/holo_green_dark" android:strokeLineCap="round" android:strokeWidth="5" /> <path android:name="path2" android:pathData=" M 20,20 L 50,20 80,20" android:strokeColor="@android:color/holo_green_dark" android:strokeLineCap="round" android:strokeWidth="5" /> </group> </vector>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:interpolator="@android:anim/bounce_interpolator" android:propertyName="pathData" android:valueFrom=" M 20,80 L 50,80 80,80" android:valueTo=" M 20,80 L 50,50 80,80" android:valueType="pathType" />
3、定義AnimatedVectorDrawable連接配接VectorDrawable和objectAnimator<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:interpolator="@android:anim/bounce_interpolator" android:propertyName="pathData" android:valueFrom=" M 20,20 L 50,20 80,20" android:valueTo=" M 20,20 L 50,50 80,20" android:valueType="pathType" />
4、布局檔案中使用這個AnimatedVectorDrawable<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/trick"> <target android:name="path1" android:animation="@anim/anim_path1" /> <target android:name="path2" android:animation="@anim/anim_path2" /> </animated-vector>
5、代碼中啟動動畫,可以在點選事件中寫這些<ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/trick_anim" android:id="@+id/image"/>
ImageView image = (ImageView) findViewById(R.id.image); Drawable drawable = image.getDrawable(); if (drawable instanceof Animatable) { ((Animatable) drawable).start(); }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 7.6.5.2 模拟三球儀
1、定義我們的VectorDrawable
2、定義兩個objectAnimator,代碼都是一樣的<?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 android:name="sun" android:pivotX="60" android:pivotY="50" android:rotation="0"> <path android:name="path_sun" android:fillColor="@android:color/holo_blue_light" android:pathData=" M 50,50 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" /> <group android:name="earth" android:pivotX="75" android:pivotY="50" android:rotation="0"> <path android:name="path_earth" android:fillColor="@android:color/holo_orange_dark" android:pathData=" M 70,50 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" /> <group> <path android:fillColor="@android:color/holo_green_dark" android:pathData=" M 90,50 m -5 0 a 4,4 0 1,0 8 0 a 4,4 0 1,0 -8,0" /> </group> </group> </group> </vector>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" />
3、定義AnimatedVectorDrawable連接配接VectorDrawable和objectAnimator<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" />
4、布局檔案中使用這個AnimatedVectorDrawable<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/earth_moon_system"> <target android:name="sun" android:animation="@anim/anim_sun" /> <target android:name="earth" android:animation="@anim/anim_earth" /> </animated-vector>
5、代碼中啟動動畫<ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/sun_system" />
ImageView image = (ImageView) findViewById(R.id.image); Drawable drawable = image.getDrawable(); if (drawable instanceof Animatable) { ((Animatable) drawable).start(); }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 7.6.5.3 軌迹動畫
1、定義我們的VectorDrawable
2、定義兩個objectAnimator,代碼都是一樣的<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="160dp" android:height="30dp" android:viewportHeight="30" android:viewportWidth="160"> <path android:name="search" android:pathData="M141 , 17 A9 ,9 0 1 , 1 ,142 , 16 L149 ,23" android:strokeAlpha="0.8" android:strokeColor="#ff3570be" android:strokeLineCap="square" android:strokeWidth="2" /> <path android:name="bar" android:pathData="M0,23 L149 ,23" android:strokeAlpha="0.8" android:strokeColor="#ff3570be" android:strokeLineCap="square" android:strokeWidth="2" /> </vector>
3、定義AnimatedVectorDrawable連接配接VectorDrawable和objectAnimator<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:interpolator="@android:interpolator/accelerate_decelerate" android:propertyName="trimPathStart" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" />
4、布局檔案中使用這個AnimatedVectorDrawable<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/searchbar"> <target android:name="search" android:animation="@anim/anim_searchbar" /> </animated-vector>
5、代碼中啟動動畫<ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/search_anim" />
ImageView image = (ImageView) findViewById(R.id.image); Drawable drawable = image.getDrawable(); if (drawable instanceof Animatable) { ((Animatable) drawable).start(); }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 SVG動畫的幾個基本步驟都是一樣的:
1、定義VectorDrawable,相當于整一個靜态的圖檔
2、定義ObjectAnimator,相當于建立一個動畫
3、定義AnimatedVectorDrawable去連接配接以上兩個玩意兒
4、在布局檔案中使用這個AnimatedVectorDrawable,ImageView的src中使用就行
5、在代碼中啟動動畫
7.7 動畫特效
7.7.1 靈動菜單
因為具有互動性,必須使用屬性動畫,設定相應的插值器就可以實作了
布局檔案:
Activity檔案:<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_b" android:src="@drawable/b" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_c" android:src="@drawable/c" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_d" android:src="@drawable/d" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_e" android:src="@drawable/e" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView_a" android:src="@drawable/a" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> </RelativeLayout>
public class PropertyTest extends Activity implements View.OnClickListener { private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c, R.id.imageView_d, R.id.imageView_e}; private List<ImageView> mImageViews = new ArrayList<ImageView>(); private boolean mFlag = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.property); for (int i = 0; i < mRes.length; i++) { ImageView imageView = (ImageView) findViewById(mRes[i]); imageView.setOnClickListener(this); mImageViews.add(imageView); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.imageView_a: if (mFlag) { startAnim(); } else { closeAnim(); } break; default: Toast.makeText(PropertyTest.this, "" + v.getId(), Toast.LENGTH_SHORT).show(); break; } } private void closeAnim() { ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0), "alpha", 0.5F, 1F); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1), "translationY", 200F, 0); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2), "translationX", 200F, 0); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3), "translationY", -200F, 0); ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4), "translationX", -200F, 0); AnimatorSet set = new AnimatorSet(); set.setDuration(500); set.setInterpolator(new BounceInterpolator()); set.playTogether(animator0, animator1, animator2, animator3, animator4); set.start(); mFlag = true; } private void startAnim() { ObjectAnimator animator0 = ObjectAnimator.ofFloat( mImageViews.get(0), "alpha", 1F, 0.5F); ObjectAnimator animator1 = ObjectAnimator.ofFloat( mImageViews.get(1), "translationY", 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat( mImageViews.get(2), "translationX", 200F); ObjectAnimator animator3 = ObjectAnimator.ofFloat( mImageViews.get(3), "translationY", -200F); ObjectAnimator animator4 = ObjectAnimator.ofFloat( mImageViews.get(4), "translationX", -200F); AnimatorSet set = new AnimatorSet(); set.setDuration(500); set.setInterpolator(new BounceInterpolator()); set.playTogether( animator0, animator1, animator2, animator3, animator4); set.start(); mFlag = false; } }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 7.7.2 計時器動畫
在這裡使用了ValueAnimator,來回顧一下
public class TimerTest extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.timer); } public void tvTimer(final View view) { ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100); valueAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ((TextView) view).setText("$ " + (Integer) animation.getAnimatedValue()); } }); valueAnimator.setDuration(3000); valueAnimator.start(); } }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結 7.7.3 下拉展開動畫
還是使用ValueAnimator來實作
布局檔案,兩個不同的LinearLayout來顯示:
Activity檔案:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:onClick="llClick" android:background="@android:color/holo_blue_bright" android:orientation="horizontal"> <ImageView android:id="@+id/app_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:gravity="left" android:text="Click Me" android:textSize="30sp" /> </LinearLayout> <LinearLayout android:id="@+id/hidden_view" android:layout_width="match_parent" android:layout_height="40dp" android:background="@android:color/holo_orange_light" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="gone"> <ImageView android:src="@mipmap/ic_launcher" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <TextView android:id="@+id/tv_hidden" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textSize="20sp" android:text="I am hidden" /> </LinearLayout> </LinearLayout>
public class DropTest extends Activity { private LinearLayout mHiddenView; private float mDensity; private int mHiddenViewMeasuredHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.drop); mHiddenView = (LinearLayout) findViewById(R.id.hidden_view); // 擷取像素密度 mDensity = getResources().getDisplayMetrics().density; // 擷取布局的高度 mHiddenViewMeasuredHeight = (int) (mDensity * 40 + 0.5); } public void llClick(View view) { if (mHiddenView.getVisibility() == View.GONE) { // 打開動畫 animateOpen(mHiddenView); } else { // 關閉動畫 animateClose(mHiddenView); } } private void animateOpen(final View view) { view.setVisibility(View.VISIBLE); ValueAnimator animator = createDropAnimator( view, 0, mHiddenViewMeasuredHeight); animator.start(); } private void animateClose(final View view) { int origHeight = view.getHeight(); ValueAnimator animator = createDropAnimator(view, origHeight, 0); animator.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { view.setVisibility(View.GONE); } }); animator.start(); } private ValueAnimator createDropAnimator( final View view, int start, int end) { ValueAnimator animator = ValueAnimator.ofInt(start, end); animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.height = value; view.setLayoutParams(layoutParams); } }); return animator; } }
![]()
Android群英傳讀書筆記——第七章:Android動畫機制與使用技巧第七章目錄第七章讀書筆記總結
總結
這一章的動畫總體來說還是比較簡單,就是幾個Android動畫架構的使用
- 視圖動畫Animation,無法互動
- 屬性動畫Animator,可以實作互動,Google更加提倡,可以實作更加豐富的動畫效果
- 布局動畫,ViewGroup中添加子View是的一個過渡動畫效果
- Android 5.X SVG矢量動畫機制,比如一些點選事件的動畫效果可以用矢量動畫來實作