Android 群英傳筆記
第一章Android體系與系統(tǒng)架構(gòu)
第二章 Android開發(fā)工具及技巧
第三章 Android控件架構(gòu)與事件攔截機制
第四章 ListView 使用技巧
第五章 Android Scroll 分析
第六章 Android 繪圖機制與屏幕適配
第七章 Android 動畫機制與使用技巧
第八章 Activity與Activity調(diào)用棧分析
第九章 Android 系統(tǒng)信息與安全機制
第十章 Android性能優(yōu)化
本文出自:
http://www.itdecent.cn/u/a1251e598483
Android動畫效果一直是人家中十分重要的一部分,從早期的Android版本中,由于動畫機制和繪圖機制的不健全,Android的人機交互備受詬病,Android從4.X開始,特別是5.X,動畫越來越完善了,Google也開始重視這一方面了,我們本章學(xué)習(xí)的主要內(nèi)容有
- Android視圖動畫‘
- Android屬性動畫
- Android動畫實例
Android View動畫框架
Animation動畫框架定義了透明度,旋轉(zhuǎn),縮放個移動等幾種動畫,而且控制了整個的View,實現(xiàn)原理是每次繪制視圖的時候View所在的ViewGroup中drawChild函數(shù)獲取該View的Animation的Transformation值,然后調(diào)用了canvas.concat方法,通過矩陣運算完成動畫幀,如果動畫沒有完成則繼續(xù)調(diào)用invalidate()方法啟動下回繪制來驅(qū)動動畫,從而完成整個動畫的繪制
視圖動畫使用簡單,效果豐富,它提供了AlphaAnimation,RotateAnimatio,TranslateAnimation,ScaleAnimation四種動畫方式,并提供了Animationset動畫集合,混合使用多種動畫,在Android3.0之前,視圖動畫一家獨大,但隨著Android3.0之后屬性動畫框架的推出它的風(fēng)光就大不如前了。相比屬性動畫,視圖動畫的一個非常大的缺陷就是不具備交互性,當(dāng)某個元件發(fā)生視圖動畫后,其響應(yīng)事件的位置還依然在動畫前的地方,所以視圖動畫只能做普通的顯示效果,避免交互的發(fā)生,但是它的優(yōu)點也非常明顯,即效率比較高且使用方便。視圖動畫使用非常簡單, 不僅可以通過XML文件來描述一個動畫過程,同樣也可以使用代碼來控制整 個動畫過程
視圖動畫
下面這個實例就列舉了一些簡單的視圖動畫使用方法
- 透明動畫
為視圖增加透明度的變換動畫
AlphaAnimation al = new AlphaAnimation(0,1);
al.setDuration(2000);
alpha.startAnimation(al);
- 旋轉(zhuǎn)動畫
RotateAnimation ro = new RotateAnimation(0,300,100,100);
ro.setDuration(2000);
rotate.setAnimation(ro)
- 平移動畫
TranslateAnimation tr = new TranslateAnimation(0,200,0,300);
tr.setDuration(2000);
translate.setAnimation(tr);
- 縮放動畫
ScaleAnimation sc = new ScaleAnimation(0,2,0,2);
sc.setDuration(2000);
scale.setAnimation(sc);
- 動畫集合
AnimationSet setAnimation = new AnimationSet(true);
setAnimation.setDuration(2000);
AlphaAnimation als = new AlphaAnimation(0,1);
als.setDuration(2000);
setAnimation.addAnimation(als);
RotateAnimation ros = new RotateAnimation(0,300,100,100);
ros.setDuration(2000);
setAnimation.addAnimation(ros);
set.startAnimation(setAnimation);
當(dāng)然,有動畫,就有監(jiān)聽,我們來監(jiān)聽一下動畫,以透明動畫為例
AlphaAnimation al = new AlphaAnimation(0,1);
al.setDuration(2000);
alpha.startAnimation(al);
al.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
Log.i("Animation","開始");
}
@Override
public void onAnimationEnd(Animation animation) {
Log.i("Animation","結(jié)束");
Toast.makeText(MainActivity.this,"動畫結(jié)束",Toast.LENGTH_LONG).show();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
Android屬性動畫分析
屬性動畫在Animator框架里的,用的最多的也就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進行更精細(xì)化的控制,只控制一個對象的屬性,而使用多個ObjectAnimator組合到AnimatorSet形成一個動畫,而且ObjectAnimator能夠自動驅(qū)動,單證各種好處,我們來看一下
- ObjectAnimator
ObjectAnimator是屬性動畫框架中最重要的實行類,創(chuàng)建一個ObjectAnimator只需通過他 的靜態(tài)工廠類直接返回一個ObjectAnimator對象,參數(shù)包括一個對象和對象的屬性名字,但這 個屬性必須有g(shù)et和對函數(shù),內(nèi)部會通過Java反射機制來調(diào)用set函數(shù)修改對象屬性值.同樣 你也可以調(diào)用setIn設(shè)置相應(yīng)的差值器。 下面這個小例子就完成了一個非常簡單的平 移動畫,
在前面的講解中說到,以前的動畫框架所產(chǎn)生的動畫,并不能改變事件響應(yīng)的位置,它只是單純地修改了顯示.如果使用舊的視圖動畫產(chǎn)生上面的效果,那么按鈕的實際點擊有效區(qū)依然在原來的地方,點擊移動后的地方是不會有點擊事件發(fā)生的.而屬性動圓則不同,由于它真實地改變了一個View的屬性,所以事件響應(yīng)的區(qū)域也同樣發(fā)生了改變,這時候點擊移動后的按鈕, 就會響應(yīng)點擊事件了
讓我們來看看這個簡單的平移動畫是如何實現(xiàn)的.麻雀雖小五臟俱全,這個簡單的例子基本上就涵蓋了ObjectAnimator的所有知識
ObjectAnimator ob = ObjectAnimator.ofFloat(object,"translationX",300);
ob.setDuration(2000);
ob.start();
通過ObjectAnimator的靜態(tài)工廠方法,創(chuàng)建個ObjectAnimator對象,第一個參數(shù)自然是要操縱的view,第二個參數(shù)則是要操縱的屬性 而最后個參數(shù)是一個可變數(shù)組參數(shù),需要傳遞進去該屬性變化的一個取值過程,
不過,在使用ObjectAnimator的時候,有一點是非常重要的,就是操縱的set,get方法,不然ObjectAnimator是無效的,下面我們具體舉一些值
translationX和 translationY:這兩個屬性作為一種增量來控制著View對象從它布局容器的左上角坐標(biāo)便宜的位置。
rotation、rotationX和rotationY:這三個屬性控制View對象圍繞支點進行2D和3D旋轉(zhuǎn)
scaleX和scaleY. 這兩個屬性控制著View對象圍繞它的支點進行2D縮放。
pivotX和pivotY:這兩個屬性控制著view對象的支點位置,圍繞這個支點進行旋轉(zhuǎn)和縮放變換處理,默認(rèn)情況下,該支點的位置就是View對象的中心點。
x和y這是兩個簡單實用的屬性,它描述了View對象在它的容器中的最終位置,它是最初的左上角坐標(biāo)和 translationX和 translationY值的累計和
alpha:它表示View對象的alpha透明度,默認(rèn)值是1(不透明),0代表完全透明(不可見)
特別注意,引號里面的單詞一定要寫正確,不然,看不到效果的
由以上可知,視圖動畫所實現(xiàn)的動畫效果,在這里基本都已經(jīng)包含了,那么如果一個屬性沒有g(shù)et,set方法,屬性動畫是不是就束手無策了答案當(dāng)然是否定的,google在應(yīng)用層提供了兩種方案來解決這個問題, 一個是通過自定義一個屬性類或者包裝類,來間接地給這個屬性增加get方法:或者通過ValusAnimator來實現(xiàn),ValusAnimator在后面的內(nèi)容中會講到, 這里先來看看如何使用包裝類的方法給一個屬性增加set,get方法:
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();
}
}
通過上面的代碼就給一個屬性包裝上了一層,并且提供set,get方法,使用時操作就行了
WrapperView vi = new WrapperView(alpha);
ObjectAnimator.ofInt(vi,"width",500).setDuration(2000).start();
- PropertyValuesHolder
這個類類似視圖動畫中的AnimationSet,就是把動畫給組合起來,在屬性動畫中,如果針對一個對象的多個屬性,就同時需要多個動畫了,可以使用PropertyValuesHolder,來實現(xiàn),比如需要在平移的過程中,同時改變x,y的縮放,可以這樣實現(xiàn)
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0,1f);
ObjectAnimator.ofPropertyValuesHolder(button3,pvh1,pvh2,pvh3).setDuration(1000).start();
- ValueAnimator
ValueAnimator這個屬性在動畫當(dāng)中有很大的地位,雖然不像ObjectAnimator那樣,耀眼,但是他確實屬性動畫的核心所在,ObjectAnimator也是繼承自他
public final class ObjectAnimator extends ValueAnimator
ValueAnimator本身不提供任何動畫,他更像是一個數(shù)值發(fā)生器,用來產(chǎn)生一定具有規(guī)律的數(shù)字,從而讓調(diào)用者控制動畫的整個過程,我們舉個例子來說明
ValueAnimator va = ValueAnimator.ofFloat(0,100);
//除了 可以ofFloat 也可以ofInt 產(chǎn)生整數(shù),可以在里面處理自己想要的動畫效果
va.setTarget(value);
va.setDuration(2000).start();
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float values = (float) animation.getAnimatedValue();
Log.i("數(shù)值",values+"");
}
});
- 動畫事件的監(jiān)聽
一個完整的動畫是具有,start,repeat,end,cancel四個過程的,通過Android的接口,我們很容易監(jiān)聽到這幾個事件
ob.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) {
}
});
當(dāng)然,大部分的場景嗎,我們只關(guān)心動畫結(jié)束,所以,Android也提供了一個AnimatorLisistenerAdapter來讓你自己選擇監(jiān)聽事件
ob.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
- AnimatorSet
對于一個屬性同時作用在一個view上,前面已經(jīng)有一個PropertyValuesHolder了,而AnimatorSet不僅能實現(xiàn),而且能更精準(zhǔn)的控制順序,同樣是實現(xiàn)PropertyValuesHolder的動畫,AnimatorSet是這樣實現(xiàn)的
ObjectAnimator animator1 = ObjectAnimator.ofFloat(alpha, "translationX", 300f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(alpha, "scaleX", 1f, 0, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(alpha, "scaleY", 1f, 0, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(2000);
set.playTogether(animator1,animator2,animator3);
set.start();
在屬性動畫中,AnimatorSet正是通過playTogether等方法控制多個動畫協(xié)同工作,從而控制播放順序的
- 在XML中定義動畫
屬性動畫同樣的可以定義在xml中
首先在 res 文件夾下建一個animator 文件夾 在這個文件夾中創(chuàng)建一個animator 類型的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>
在代碼中引用
Animator animator = AnimatorInflater.loadAnimator(AnimationActivity.this,R.animator.scale);
animator.setTarget(button4);
animator.start();
- View的animate方法
在Android3.0,Google給view增加了animate方法直接來驅(qū)動屬性動畫,代碼如下,我們可以發(fā)現(xiàn),其實animate就是屬性動畫的一種縮寫
button4.animate().alpha(0).y(300).setDuration(2000).withStartAction(new Runnable() {
@Override
public void run() {
}
}).withEndAction(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
}).start();
Android 布局動畫
所謂的布局動畫,就是作用在ViewGruop中給View添加的過渡效果,最簡單的方法是在xml中打開
android:animateLayoutChanges="true"
通過以上代碼設(shè)置, 當(dāng)ViewGroup 添加View 時, 子View 會呈現(xiàn)逐漸顯示的過渡效果, 不過這都是Android自帶的效果,我們還可以通過LayoutAnimationController來定義
ll = (LinearLayout) findViewById(R.id.ll);
//設(shè)置過渡動畫
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
sa.setDuration(2000);
LayoutAnimationController lc = new LayoutAnimationController(sa, 0.5f);
lc.setOrder(LayoutAnimationController.ORDER_NORMAL);
//設(shè)置布局動畫
ll.setLayoutAnimation(lc);
LayoutAnimationController的第一個參數(shù) 是需要作用的動畫,第二個參數(shù),是每個子View顯示的delay 時間,當(dāng)delay 時間不為0時,可以設(shè)置子View 顯示的順序
- 1.LayoutAnimationController.ORDER_NORMAL 順序
- 2.LayoutAnimationController.ORDER_RANDOM 隨機
- 3.LayoutAnimationController.ORDER_REVEESE 反序
- Interpolators(插值器)
插值器在動畫中是一個非常重要的概念,我們通過插值器可以定義動畫變換速率,這一點非常類似物理中的加速度,其作用主要是目標(biāo)變化對應(yīng)的變化,同樣的一個動畫變換起始值,在不同的插值器的作用下,每個單位時間內(nèi)所達(dá)到的變換值都是不一樣的,例如一個平移動畫,如果使用線性插值器,那么在持續(xù)時間內(nèi)單位時間所移動的距離都是一樣的,如果使用加速度插值器,那么單位時間內(nèi)所移動的速度越來越快,大家如果把插值器的概念理解為一個人進行萬米長跑,規(guī)定一個小時到達(dá),有的人怕時間來不及一開始就加速跑但是到后面速度越來越慢,而有的人開始節(jié)省體力,所以開始跑的比較慢,后來越跑越快直到終點,不管怎么跑,最終他們的都是在規(guī)定的時間到達(dá)終點,唯一不同的是他們的跑的速度不同,通過這個例子,我們可以很好的理解插值器的概念
- 自定義動畫
創(chuàng)建自定義動畫很簡單,只需要實現(xiàn)applyTransformation的邏輯就可以,不過通常情況下,我們還要覆蓋父類的initialize方法來完成一些初始化工作,
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
}
第一個參數(shù)interpolatedTime是前面說的插值器的時間因子,這個因子是由動畫當(dāng)前完成的百分比和當(dāng)前時間對應(yīng)的差值計算的,取值范圍在0-1.0,第二個參數(shù)就非常簡單了,她是矩陣的封裝類,一般使用這個類獲取當(dāng)前的矩陣對象,代碼如下
Matrix matrix = t.getMatrix();
通過改變獲得的matrix 對象,可以將動畫效果實現(xiàn),而對于matrix 的變換操作,基本上可以實現(xiàn)任何效果
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
Matrix matrix = t.getMatrix();
matrix.preScale(1, 1 - interpolatedTime, width,height);
super.applyTransformation(interpolatedTime, t);
}
當(dāng)然我們可以設(shè)置更加精準(zhǔn)的插值器,,從而對不同的過程采用不同的動畫效果,模擬的更加逼真
接下來我們結(jié)合矩陣,并且使用Canmera來實現(xiàn)一個3D的效果,要注意的是,這里所指的Camera不是相機,而是這個類,他封裝了openGl的3D動畫,我們繼續(xù)用代碼來實現(xiàn)
@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());
w = width / 2;
h = height / 2;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
Matrix matrix = t.getMatrix();
// matrix.preScale(1, 1 - interpolatedTime, w,h);
mCamera.save();
//設(shè)置旋轉(zhuǎn)角度
mCamera.rotate(0, 180, 360);
mCamera.restore();
//通過pre方法設(shè)置矩形作用前的偏移量來改變旋轉(zhuǎn)中心
matrix.preTranslate(w, h);
matrix.postTranslate(-w, -h);
super.applyTransformation(interpolatedTime, t);
}
通過以上的方法,就可以實現(xiàn)了
Android SVG
- 可伸縮矢量圖形
- 定義用于網(wǎng)絡(luò)的基于矢量的圖形
- 使用xml格式定義圖形
- 圖片在放大或者改變尺寸的情況下其圖形質(zhì)量不會有所損失
- 萬維網(wǎng)聯(lián)盟的標(biāo)準(zhǔn)
- 與諸多DOM和XSL之類的W3C標(biāo)準(zhǔn)是一個整體
SVG在web上應(yīng)用非常廣泛,在Android5.X之前的Android版本上,大家可以通過一些第三方庫在Android中使用SVG,而在Android5.X后,Android中添加了對< path >標(biāo)簽的支持,從而讓開發(fā)者可以使用SVG來創(chuàng)建更加豐富的動畫效果,那么SVG對傳統(tǒng)的Bitmap,究竟有什么好處呢?bitmap通過每個像素點上存儲色彩信息來表達(dá)圖像,而SVG是一個繪圖標(biāo)準(zhǔn),與之相對,最大的優(yōu)勢是SVG放大不會失真,而且bitmap需要不同分辨率適配,SVG不需要
< path >標(biāo)簽
使用< path >標(biāo)簽來創(chuàng)建SVG,就是用指令的方式來控制一支畫筆,列入,移動畫筆來到某一個坐標(biāo)位置,畫一條線,畫一條曲線,結(jié)束,< path >標(biāo)簽所支持的指令大致有一下幾種
M = moveto(M X,Y):將畫筆移動到指定的坐標(biāo)位置,但未發(fā)生繪制
L = lineto(L X,Y):畫直線到指定的位置
H = horizontal lineto( H X):畫水平線到指定的X坐標(biāo)位置
V = vertical lineto(V Y ):畫垂直線到指定的Y坐標(biāo)
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() 關(guān)閉路徑
使用上面的指令時,需要注意的幾點
- 坐標(biāo)軸以(0,0)位中心,X軸水平向右,Y軸水平向下
- 所有指令大小寫均可,大寫絕對定位,參照全局坐標(biāo)系,小寫相對定位,參照父容器坐標(biāo)系
- 指令和數(shù)據(jù)間的空格可以無視
- 同一指令出現(xiàn)多次可以用一個
SVG常見指令
L
繪制直線的指令是“L”,代表從當(dāng)前點繪制直線到給定點,“L”之后的參數(shù)是一個點坐標(biāo),如“L 200 400”繪制直線,同時,還可以使用“H”和“V”指令來繪制水平豎直線,后面的參數(shù)是x坐標(biāo)個y坐標(biāo)
M
M指令類似Android繪圖中的path類moveto方法,即代表畫筆移動到某一點,但并不發(fā)生繪圖動作
A
A指令是用來繪制一條弧線,且允許弧線不閉合,可以把A指令繪制的弧度想象成橢圓的某一段A指令一下有七個指令
- RX,RY指所有的橢圓的半軸大小
- XROTATION 指橢圓的X軸和水平方向順時針方向的夾角,可以想象成一個水平的橢圓饒中心點順時針旋轉(zhuǎn)XROTATION 的角度
- FLAG1 只有兩個值,1表示大角度弧度,0為小角度弧度
- FLAG2 只有兩個值,確定從起點到終點的方向1順時針,0逆時針
X,Y為終點坐標(biāo)
SVG的指令參數(shù)非常的復(fù)雜,但是再Android中,不需要繪制太多的SVG圖像
關(guān)于SVG 可以參考這片文章,挺好的 http://www.itdecent.cn/p/0555b8c1d26a
Android動畫特效
- 衛(wèi)星菜單
當(dāng)點擊小紅點的時候,彈出菜單,并且?guī)в幸粋€緩沖的效果,這就是Google在MD中強調(diào)的動畫過渡,要怎么實現(xiàn)這個動畫呢,其實還不是就一個開始一個結(jié)束動畫,看代碼
/**
* 執(zhí)行動畫
*/
private void statAnim(){
ObjectAnimator animator0 = ObjectAnimator.ofFloat(iv0,"alpha",1F,0.5F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv1,"translationY",200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv2,"translationX",200F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv3,"translationY",-200F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(iv4,"translationX",-200F);
AnimatorSet set = new AnimatorSet();
set.setInterpolator(new BounceInterpolator());
set.playTogether(animator0,animator1,animator2,animator3,animator4);
set.start();
mFlag = false;
}
下面就是點擊事件
iv0.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mFlag){
statAnim();
}else{
closeAnim();
}
}
});
- 計時器動畫
通過這個示例,我們了解一下ValueAnimator的效果,當(dāng)用戶點擊后,數(shù)字不斷增加,好的,我們開始
package com.lgl.animations;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
/**
* 繪制SVG
* Created by LGL on 2016/4/16.
*/
public class SVGActivity extends AppCompatActivity {
private TextView tv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_svg);
tv = (TextView) findViewById(R.id.tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tvTimer(tv);
}
});
}
private void tvTimer(final View view){
ValueAnimator va = ValueAnimator.ofInt(0,100);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
( (TextView)view).setText("$"+(Integer)animation.getAnimatedValue());
}
});
va.setDuration(3000);
va.start();
}
}
- 下拉展開動畫
下面我們來實現(xiàn)一個展開的動畫,首先,XML是這樣的
<?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="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center_vertical"
android:onClick="llClick"
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:orientation="horizontal"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_hidden"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="I Am Hidden"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
為了區(qū)分兩個不同的線性布局,我們給他設(shè)置了不同的顏色背景,
package com.younger.animations;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
/**
* 下拉展開動畫
* Created by Younger on 2018/03/11.
*/
public class AnimaActivity extends AppCompatActivity {
private LinearLayout mHiddenView;
private float mDensity;
private int mHiddenViewMeasuredHeight;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_anima);
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){
animOpen(mHiddenView);
}else{
animClose(mHiddenView);
}
}
private void animOpen(final View view){
view.setVisibility(View.VISIBLE);
ValueAnimator va = createDropAnim(view,0,mHiddenViewMeasuredHeight);
va.start();
}
private void animClose(final View view){
int origHeight = view.getHeight();
ValueAnimator va = createDropAnim(view,origHeight,0);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setVisibility(View.GONE);
}
});
va.start();
}
private ValueAnimator createDropAnim(final View view,int start,int end) {
ValueAnimator va = ValueAnimator.ofInt(start, end);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = value;
view.setLayoutParams(layoutParams);
}
});
return va;
}
}
好了,就這些