您的位置:首页 > 移动开发 > Android开发

Android属性动画PropertyAnimation系列三之LayoutTransition(布局容器动画)

2015-07-09 21:38 537 查看
在上一篇中我们学习了属性动画的ObjectAnimator使用,不了解的可以看看 Android属性动画Property
Animation系列一之ObjectAnimator。这一篇我们来学点新的东西。做项目的时候应该碰到这种问题:根据不同条件显示或者隐藏一个控件或者布局,我们能想到的第一个方法就是 调用View.setVisibility()方法。虽然实现了显示隐藏效果,但是总感觉这样的显示隐藏过程很僵硬,让人不是很舒服,那么有没有办法能让这种显示隐藏有个过渡的动画效果呢?答案是肯定的,不言而喻就是LayoutTransition类了。

上效果图



实现上面的效果只需要在布局容器中添加android:animateLayoutChanges=”true”属性就ok了。不信你看

布局文件如下:

view
sourceprint?

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控件里,表示容器里面布局改变时有默认的动画效果,比如说添加控件,删除控件的时候就是默认的动画效果。

以上动画调用代码如下:

view
sourceprint?

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中去。代码如下:

view
sourceprint?

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出现的动画

view
sourceprint?

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中。

完整动画代码如下,具体解释都有注解

view
sourceprint?

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>




布局文件

view
sourceprint?

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文件,代码如下:

view
sourceprint?

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文件,码如下:

view
sourceprint?

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的动画效果了。

当然我们也可以在代码中实现这种动画效果

view
sourceprint?

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属性动画至此就基本介绍完毕了。其中基本的动画使用和实例也贴出来了,基本能满足日常开发需求,当然有更炫的动画时可以根据这些基础去实现。这么说,以后都可以不用补间动画了?貌似属性动画更加合理,因为这种动画改变的是属性而不仅仅是位置。





延伸阅读:

1、Android开发之自定义动画

2、Android电视关闭的动画效果

3、Android中Linux开机启动画面设置方法

4、android编程 简单的渐变动画

5、Android中动画学习

6、Android编程开发动画效果被遮掉的问题

7、Android Frame Animation帧动画不播放问题

8、Android开发吸入式动画效果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: