-
在上一篇中我們學習了屬性動畫的ObjectAnimator使用,不瞭解的可以看看 Android屬性動畫Property Animation系列一之ObjectAnimator。這一篇我們來學點新的東西。做項目的時候應該碰到這種問題:根據不同條件顯示或者隱藏一個控件或者佈局,我們能想到的第一個方法就是 調用View.setVisibility()方法。雖然實現了顯示隱藏效果,但是總感覺這樣的顯示隱藏過程很僵硬,讓人不是很舒服,那麼有沒有辦法能讓這種顯示隱藏有個過渡的動畫效果呢?答案是肯定的,不言而喻就是LayoutTransition類了。
上效果圖
實現上面的效果只需要在佈局容器中添加android:animateLayoutChanges=”true”屬性就ok了。不信你看
佈局文件如下:01.
<code
class
=
" hljs xml"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
05.
android:orientation=
"vertical"
>
06.
07.
<LinearLayout
08.
android:layout_width=
"match_parent"
09.
android:layout_height=
"wrap_content"
10.
android:orientation=
"horizontal"
>
11.
12.
<Button
13.
android:layout_width=
"wrap_content"
14.
android:layout_height=
"wrap_content"
15.
android:onClick=
"buttonClick"
16.
android:text=
"添加控件"
/>
17.
18.
<Button
19.
android:layout_width=
"wrap_content"
20.
android:layout_height=
"wrap_content"
21.
android:onClick=
"buttonClick1"
22.
android:text=
"移除控件"
/>
23.
</LinearLayout>
24.
25.
26.
<LinearLayout
27.
android:id=
"@+id/parent"
28.
android:layout_width=
"match_parent"
29.
android:layout_height=
"wrap_content"
30.
android:animateLayoutChanges=
"true"
31.
android:orientation=
"vertical"
></LinearLayout>
32.
33.
</LinearLayout></code>
如果佈局容器中爲添加android:animateLayoutChanges=”true”默認是麼有動畫效果的。該屬性只能用在ViewGroup控件裏,表示容器裏面佈局改變時有默認的動畫效果,比如說添加控件,刪除控件的時候就是默認的動畫效果。
以上動畫調用代碼如下:
01.
<code
class
=
" hljs java"
>
package
com.xjp.animations;
02.
03.
import
android.app.Activity;
04.
import
android.os.Bundle;
05.
import
android.view.View;
06.
import
android.view.ViewGroup;
07.
import
android.widget.Button;
08.
import
android.widget.LinearLayout;
09.
10.
/**
11.
* Description:
12.
* User: xjp
13.
* Date: 2015/5/22
14.
* Time: 15:06
15.
*/
16.
17.
public
class
LayoutAnimationActivity
extends
Activity {
18.
19.
private
LinearLayout parent;
20.
private
int
i =
0
;
21.
private
int
j =
0
;
22.
23.
@Override
24.
protected
void
onCreate(Bundle savedInstanceState) {
25.
super
.onCreate(savedInstanceState);
26.
27.
setContentView(R.layout.activity_layout_animation);
28.
29.
parent = (LinearLayout) findViewById(R.id.parent);
30.
}
31.
32.
public
void
buttonClick(View view) {
33.
addButtonView();
34.
}
35.
36.
public
void
buttonClick1(View view) {
37.
removeButtonView();
38.
}
39.
40.
private
void
addButtonView() {
41.
i++;
42.
Button button =
new
Button(
this
);
43.
button.setText(
"button"
+ i);
44.
LinearLayout.LayoutParams params =
new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
45.
ViewGroup.LayoutParams.WRAP_CONTENT);
46.
parent.addView(button, params);
47.
}
48.
49.
private
void
removeButtonView() {
50.
if
(i >
0
)
51.
parent.removeViewAt(
0
);
52.
}
53.
}
54.
</code>
是不是發現很簡單?除了佈局中添加了android:animateLayoutChanges=”true”屬性,代碼中根本不需要做任何處理就有很舒服的過渡動畫效果了。主要是添加了該屬性之後在容器中有佈局改變時系統會默認給該容器添加一個默認的動畫效果。如果你覺得上面的的效果已經很nice~了,那你就太容易滿足了,我們除了使用系統默認的佈局容器動畫,還可以自定義佈局容器動畫。現在該LayoutTransition類上場了。
LayoutTransition
該類用於當前佈局容器中有View添加,刪除,隱藏,顯示的時候定義佈局容器自身的動畫和View的動畫。也就是說當一個LinerLayout中隱藏一個view的時候,我們可以自定義 整個LinerLayout容器因爲隱藏了view而改變的動畫,同時還可以自定義被隱藏的view自己消失時候的動畫。你可以先new一個LayoutTransition對象,通過setLayoutTransition()方法將對象設置進一個佈局容器ViewGroup中去。代碼如下:
01.
<code
class
=
" hljs java"
>
private
LinearLayout container;
02.
private
LayoutTransition mTransitioner;
03.
/**
04.
* 初始化容器動畫
05.
*/
06.
private
void
initTransition() {
07.
mTransitioner =
new
LayoutTransition();
08.
container.setLayoutTransition(mTransitioner);
09.
}</code>
LayoutTransition類定義瞭如下幾種佈局容器動畫類型。
APPEARING :當view出現或者添加的時候,view出現的動畫 DISAPPEARING :當view消失或者隱藏的時候,view消失的動畫 CHANGE_APPEARING :當添加view導致佈局容器改變的時候,整個佈局容器的動畫 CHANGE_DISAPPEARING :當刪除或者隱藏view導致佈局容器改變的時候,整個佈局容器的動畫你可以自定義這些動畫,通過setAnimator() 方法把它們設置進一個 LayoutTransition 對象中去。
LayoutTransition的用法
APPEARING–view出現的動畫
1.
<code
class
=
" hljs java"
>
/**
2.
* view出現時 view自身的動畫效果
3.
*/
4.
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
null
,
"rotationY"
, 0F, 90F, 0F);
5.
mTransitioner.setAnimator(LayoutTransition.APPEARING, animator1);</code>
定義一個旋轉的屬性動畫,這裏將動畫對象置空,因爲系統內部會將添加的view設置爲動畫對象。然後調用setAnimator()方法將動畫設置進LayoutTransition對象mTransitioner中。
完整動畫代碼如下,具體解釋都有註解
001.
<code
class
=
" hljs java"
>
package
com.xjp.animations;
002.
003.
import
android.animation.Animator;
004.
import
android.animation.AnimatorListenerAdapter;
005.
import
android.animation.Keyframe;
006.
import
android.animation.LayoutTransition;
007.
import
android.animation.ObjectAnimator;
008.
import
android.animation.PropertyValuesHolder;
009.
import
android.app.Activity;
010.
import
android.os.Bundle;
011.
import
android.view.View;
012.
import
android.view.ViewGroup;
013.
import
android.widget.Button;
014.
import
android.widget.LinearLayout;
015.
016.
/**
017.
* Description:佈局動畫Demo
018.
* User: xjp
019.
* Date: 2015/5/22
020.
* Time: 15:06
021.
*/
022.
023.
public
class
LayoutAnimationActivity
extends
Activity {
024.
025.
026.
private
int
i =
0
;
027.
private
LinearLayout container;
028.
private
LayoutTransition mTransitioner;
029.
030.
@Override
031.
protected
void
onCreate(Bundle savedInstanceState) {
032.
super
.onCreate(savedInstanceState);
033.
034.
setContentView(R.layout.activity_layout_animation);
035.
036.
container = (LinearLayout) findViewById(R.id.parent);
037.
038.
initTransition();
039.
setTransition();
040.
}
041.
042.
/**
043.
* 初始化容器動畫
044.
*/
045.
private
void
initTransition() {
046.
mTransitioner =
new
LayoutTransition();
047.
container.setLayoutTransition(mTransitioner);
048.
}
049.
050.
051.
private
void
setTransition() {
052.
/**
053.
* view出現時 view自身的動畫效果
054.
*/
055.
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
null
,
"rotationY"
, 90F, 0F).
056.
setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
057.
mTransitioner.setAnimator(LayoutTransition.APPEARING, animator1);
058.
059.
/**
060.
* view 消失時,view自身的動畫效果
061.
*/
062.
ObjectAnimator animator2 = ObjectAnimator.ofFloat(
null
,
"rotationX"
, 0F, 90F, 0F).
063.
setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
064.
mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animator2);
065.
066.
/**
067.
* view 動畫改變時,佈局中的每個子view動畫的時間間隔
068.
*/
069.
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING,
30
);
070.
mTransitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING,
30
);
071.
072.
073.
/**
074.
* 爲什麼這裏要這麼寫?具體我也不清楚,ViewGroup源碼裏面是這麼寫的,我只是模仿而已
075.
* 不這麼寫貌似就沒有動畫效果了,所以你懂的!
076.
*/
077.
PropertyValuesHolder pvhLeft =
078.
PropertyValuesHolder.ofInt(
"left"
,
0
,
1
);
079.
PropertyValuesHolder pvhTop =
080.
PropertyValuesHolder.ofInt(
"top"
,
0
,
1
);
081.
PropertyValuesHolder pvhRight =
082.
PropertyValuesHolder.ofInt(
"right"
,
0
,
1
);
083.
PropertyValuesHolder pvhBottom =
084.
PropertyValuesHolder.ofInt(
"bottom"
,
0
,
1
);
085.
086.
087.
/**
088.
* view出現時,導致整個佈局改變的動畫
089.
*/
090.
PropertyValuesHolder animator3 = PropertyValuesHolder.ofFloat(
"scaleX"
, 1F, 2F, 1F);
091.
final
ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
092.
this
, pvhLeft, pvhTop, pvhRight, pvhBottom, animator3).
093.
setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
094.
changeIn.addListener(
new
AnimatorListenerAdapter() {
095.
@Override
096.
public
void
onAnimationEnd(Animator animation) {
097.
View view = (View) ((ObjectAnimator) animation).getTarget();
098.
view.setScaleX(
1
.0f);
099.
}
100.
});
101.
mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);
102.
103.
104.
/**
105.
* view消失,導致整個佈局改變時的動畫
106.
*/
107.
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
108.
Keyframe kf1 = Keyframe.ofFloat(.5f, 2f);
109.
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
110.
PropertyValuesHolder pvhRotation =
111.
PropertyValuesHolder.ofKeyframe(
"scaleX"
, kf0, kf1, kf2);
112.
final
ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(
113.
this
, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation).
114.
setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
115.
changeOut.addListener(
new
AnimatorListenerAdapter() {
116.
@Override
117.
public
void
onAnimationEnd(Animator animation) {
118.
View view = (View) ((ObjectAnimator) animation).getTarget();
119.
view.setScaleX(
1
.0f);
120.
}
121.
});
122.
mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
123.
}
124.
125.
126.
public
void
buttonClick(View view) {
127.
addButtonView();
128.
}
129.
130.
public
void
buttonClick1(View view) {
131.
removeButtonView();
132.
}
133.
134.
private
void
addButtonView() {
135.
i++;
136.
Button button =
new
Button(
this
);
137.
button.setText(
"button"
+ i);
138.
LinearLayout.LayoutParams params =
new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
139.
ViewGroup.LayoutParams.WRAP_CONTENT);
140.
container.addView(button, Math.min(
1
, container.getChildCount()), params);
141.
}
142.
143.
private
void
removeButtonView() {
144.
if
(i >
0
)
145.
container.removeViewAt(
0
);
146.
}
147.
}
148.
</code>
佈局文件
01.
<code
class
=
" hljs xml"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
03.
android:layout_width=
"match_parent"
04.
android:layout_height=
"match_parent"
05.
android:orientation=
"vertical"
>
06.
07.
<LinearLayout
08.
android:layout_width=
"match_parent"
09.
android:layout_height=
"wrap_content"
10.
android:orientation=
"horizontal"
>
11.
12.
<Button
13.
android:layout_width=
"wrap_content"
14.
android:layout_height=
"wrap_content"
15.
android:onClick=
"buttonClick"
16.
android:text=
"添加控件"
/>
17.
18.
<Button
19.
android:layout_width=
"wrap_content"
20.
android:layout_height=
"wrap_content"
21.
android:onClick=
"buttonClick1"
22.
android:text=
"移除控件"
/>
23.
</LinearLayout>
24.
25.
26.
<LinearLayout
27.
android:id=
"@+id/parent"
28.
android:layout_width=
"match_parent"
29.
android:layout_height=
"wrap_content"
30.
android:animateLayoutChanges=
"true"
31.
android:orientation=
"vertical"
></LinearLayout>
32.
33.
</LinearLayout></code>
最後來一張效果圖:
佈局動畫之layoutAnimation
很多時候我們想要在第一次加載ListView或者GridView的時候能有個動畫效果來達到一個很好的過度效果。比如下面的效果
實現這種效果只需要在佈局中添加android:layoutAnimation=”@anim/layout”屬性就好了。接下來我們來看看layout.xml動畫怎麼實現的?在res/anim目錄下新建layout.xml文件,代碼如下:1.
<code
class
=
" hljs xml"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
2.
<layoutAnimation xmlns:android=
"http://schemas.android.com/apk/res/android"
3.
android:animation=
"@anim/left"
4.
android:animationOrder=
"normal"
5.
android:delay=
"30%"
></layoutAnimation></code>
android:delay 子類動畫時間間隔 (延遲) 70% 也可以是一個浮點數 如“1.2”等
android:animationOrder=”random” 子類的顯示方式 random表示隨機
android:animationOrder 的取值有
normal 0 默認
reverse 1 倒序
random 2 隨機
android:animation=”@anim/left” 表示孩子顯示時的具體動畫是什麼代
在res/anim目錄下新建left.xml文件,碼如下:01.
<code
class
=
" hljs xml"
><?xml version=
"1.0"
encoding=
"utf-8"
?>
02.
<set xmlns:android=
"http://schemas.android.com/apk/res/android"
>
03.
<translate
04.
android:duration=
"500"
05.
android:fromXDelta=
"100%"
06.
android:fromYDelta=
"0"
07.
android:toXDelta=
"0"
08.
android:toYDelta=
"0"
/>
09.
<alpha
10.
android:duration=
"500"
11.
android:fromAlpha=
"0"
12.
android:toAlpha=
"1"
/>
13.
</set></code>
這樣就實現瞭如上ListView的動畫效果了。
當然我們也可以在代碼中實現這種動畫效果
01.
<code
class
=
" hljs cs"
>
private
void
initAinm() {
02.
//通過加載XML動畫設置文件來創建一個Animation對象;
03.
Animation animation = AnimationUtils.loadAnimation(
this
, R.anim.left);
04.
//得到一個LayoutAnimationController對象;
05.
LayoutAnimationController lac =
new
LayoutAnimationController(animation);
06.
//設置控件顯示的順序;
07.
lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
08.
//設置控件顯示間隔時間;
09.
lac.setDelay(
1
);
10.
//爲ListView設置LayoutAnimationController屬性;
11.
listView.setLayoutAnimation(lac);
12.
}</code>
通過AnimationUtils.loadAnimation加載item的動畫來獲得一個Animation對象,然後將Animation對象設置到LayoutAnimationController中來獲得LayoutAnimationController對象,配置LayoutAnimationController對象的一些屬性。最後將LayoutAnimationController對象設置到ListView中。
注意
layoutAnimation動畫不僅僅限於ListView,GridView中,也可用於一切ViewGroup中。具體怎麼用就看項目需求了。
總結
Android屬性動畫至此就基本介紹完畢了。其中基本的動畫使用和實例也貼出來了,基本能滿足日常開發需求,當然有更炫的動畫時可以根據這些基礎去實現。這麼說,以後都可以不用補間動畫了?貌似屬性動畫更加合理,因爲這種動畫改變的是屬性而不僅僅是位置。