安卓动画学习-布局动画进阶
- 上篇讲到了实现ViewGroup第一次创建时候子View进入动画
- 可是缺点也很明显,他只会在第一次创建的时候产生动画
- 最后通过查看ViewGroup官方文档可知,我们是可以手动控制这个动画的
- 接下来继续探索吧
animateLayoutChanges
- 还是在ViewGroup的文档里面发现了这个属性
- 官方给的介绍是:
android:animateLayoutChanges
Defines whether changes in layout (caused by adding and removing items) should cause a LayoutTransition to run. When this flag is set to true, a default LayoutTransition object will be set on the ViewGroup container and default animations will run when these layout changes occur.
May be a boolean value, such as "true" or "false".
Related methods:
setLayoutTransition(LayoutTransition)
- 大概意思是,当布局中的子项删除或者增加的时候,如果这个属性为true,就会运行默认的LayoutTransition动画
- 还有一个相关方法,setLayoutTransition(LayoutTransition),那么很自然就能猜到吧,如果给这个属性为true,那么就会运行默认的动画或者运行你设置的动画
- 那么很自然的猜到,即便你不设置这个LayoutTransition,他内部也会有一个自己默认的LayoutTransition动画的,so,直接去看这个LayoutTransition东西吧
LayoutTransition
- 难受,我这里直接贴谷歌翻译过来的文档了,有需求的小伙伴可以自行去观看官方文档
- 该类在ViewGroup对象的布局更改中启用自动动画。要为布局容器启用转场,请创建一个LayoutTransition对象并通过调用将其设置在任何ViewGroup上setLayoutTransition(LayoutTransition)。这会导致默认动画在物品添加到该容器或从该容器移除时运行。要指定自定义动画,请使用该setAnimator()方法。
- 剩下的一大段字有点多,这里我简单说一下我的理解吧
- 就是说,我们在添加子项或者删除子项的时候,总会涉及到,被操作子项的进场动画或者消失动画,以及其他动画为弥补这个被操作子项因为消失多出的空间或者因为创建进场而需要的控件而是其他子项做出的动画,这些动画的一些属性都是我们不得不考虑的
- 上面一段话读者看着理解吧,实在不理解也没关系,接下来慢慢讲解就懂了
- 我们接着看LayoutTransition这个类的其他东西吧
LayoutTransition的常量
常量 |
意义 |
int APPEARING |
一个标志,指示在容器中出现的那些项目上运行的动画。 |
int CHANGE_APPEARING |
一个标志,表示在由于容器中出现新项目而正在更改的那些项目上运行的动画。 |
int CHANGE_DISAPPEARING |
一个标志,表示在由于某个项目从容器中消失而正在更改的项目上运行的动画。 |
int CHANGING |
一个标志,表示在由于布局更改而导致正在更改的项目上运行的动画,这些更改不是由向容器添加项目或从容器中移除项目引起的。 |
int DISAPPEARING |
一个标志,指示在从容器中消失的那些项目上运行的动画。 |
- 可以看到,四个常量分别对应我们上面讲到的四种不同的动画
- CHANGING对应的是他们之外的,比方说,当想通过拖动某个子项让他改变位置时,这个时候就应用这个动画,还是继续往下看吧,边看边理解
- 只有一个无参的构造方法,没啥说的
- 再看看有什么能用到的方法吧
LayoutTransition的方法
方法 |
用法 |
void addTransitionListener(LayoutTransition.TransitionListener listener) |
添加一个监听器,当由于布局处理而导致视图边界发生更改时将会调用该监听器。 |
Animator getAnimator(int transitionType) |
获取可能运行的其中一种转换类型期间使用的动画。 |
long getDuration(int transitionType) |
获取此转换使用的其中一个动画对象的持续时间。 |
boolean isChangingLayout() |
如果动画正在运行动画布局相关的属性,则返回true。 |
boolean isRunning() |
如果此转换中的任何动画当前正在运行,则返回true。 |
boolean isTransitionTypeEnabled(int transitionType) |
返回是否为此LayoutTransition对象启用指定的transitionType。 |
void setAnimator(int transitionType, Animator animator) |
设置可能运行的其中一种转换类型期间使用的动画。 |
void setDuration(int transitionType, long duration) |
设置可能运行的其中一种转换类型期间使用的动画。 |
void setDuration(long duration) |
设置此过渡对象的所有动画使用的持续时间。 |
void setStagger(int transitionType, long duration) |
设置在其中一个更改动画期间开始每个动画之间的延迟时间。 |
- 如果结合前面的介绍,对这些方法的具体用法应该也不会太难理解
- 接下来就具体实践一下吧
实践
- 先看效果
- 再看代码
static int dis = 0;
@RequiresApi(api = Build.VERSION_CODES.O)
private void setLinearAnimationMore() {
final LinearLayout layout = findViewById(R.id.main_Ll);
Button add = findViewById(R.id.main_ll_Add);
final Button remove = findViewById(R.id.main_ll_Remove);
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Button button = new Button(getBaseContext());
button.setText("新加button"+ dis++);
button.setAlpha(0);
layout.addView(button,2);
}
});
remove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int cnt = layout.getChildCount();
if(cnt > 2){
layout.removeViewAt(2);
}
}
});
LayoutTransition transition = new LayoutTransition();
ObjectAnimator animator = ObjectAnimator.ofFloat(null, "translationX", -1000f, 0f);
ObjectAnimator animator1 = ObjectAnimator.ofArgb(null,"backgroundColor",Color.BLUE,Color.GREEN);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(null,"alpha",0,1);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(animator).with(animator1).with(animator2);
transition.setAnimator(LayoutTransition.APPEARING,animatorSet);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(null, "translationX", 0f,-1000f);
ObjectAnimator animator4 = ObjectAnimator.ofArgb(null,"backgroundColor",Color.GREEN,Color.BLUE);
ObjectAnimator animator5 = ObjectAnimator.ofFloat(null,"alpha",1,0);
AnimatorSet animatorSet1 = new AnimatorSet();
animatorSet1.play(animator3).with(animator4).with(animator5);
transition.setAnimator(LayoutTransition.DISAPPEARING, animatorSet1);
transition.setDuration(3000);
layout.setLayoutTransition(transition);
}
<LinearLayout
android:id="@+id/main_Ll"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/main_ll_Add"
android:text="添加"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/main_ll_Remove"
android:text="移除"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
- 其实代码也很简单,跟着我简单分析一下吧
- xml布局就两个按钮
- 然后看实现java代码
- 先给两个按键设置监听,这些不讲,很容易理解
- 再来创建一个我们自己的入场动画以及一个出场动画,对动画创建不懂的童鞋可以去看我的前几篇博客
- 然后分别按照不同的类型设置到LayoutTransition类实例当中,系统会根据不同的Type知道你这个是什么时期的动画,比方LayoutTransition.DISAPPEARING,是我们在删除子项的时候被删除子项的动画,这个根据前面的讲解以及这里的应用相信已经很明白了
- 然后设置动画时长,可以单独设置每种类型的时长,我在这里偷懒直接设置了所有动画的时长
- 然后将LayoutTransition的实例设置到VIewGroup当中就ok
- 注意
- 我在实验添加的时候,发现他是先创建出这个子项,然后在运行我们设置的动画,因为我想要的效果是让他从左边出来,如果他先直接出现在屏幕中明显有点难看,所以我在创建的时候事先将他的透明度设置为0,让他看不见,在完成我们的动画之后再让他显示,这样子合情合理
- 还有一个问题,我发现在删除的时候,被删除子项还没有完全移除出屏幕的时候,底下那些子项就已经往上移动了,这点是因为我设置的时间太久看的比较明显,如果设置的时间短一点应该就看不出来了,或者我们也可以通过设置动画与动画之间的时间来避免这个效果,这个就看具体情况具体对待吧