首页 > 嗟来之食 > 自定义ViewGroup添加布局动画
2018
05-05

自定义ViewGroup添加布局动画

声明几个属性值:

<declare-styleable name="GridImageViewGroup">
<attr name="childVerticalSpace" format="dimension"/>
<attr name="childHorizontalSpace" format="dimension"/>
<attr name="columnNum" format="integer"/>
</declare-styleable>

GridImageViewGroup.java 代码:

1 public class GridImageViewGroup extends ViewGroup {
2 private int childVerticalSpace = 0;
3 private int childHorizontalSpace = 0;
4 private int columnNum = 3;
5 private int childWidth = 0;
6 private int childHeight = 0;
7
8
9 public GridImageViewGroup(Context context, AttributeSet attrs) {
10 super(context, attrs);
11 TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.GridImageViewGroup);
12 if (attributes != null) {
13 childVerticalSpace = attributes.getDimensionPixelSize(R.styleable.GridImageViewGroup_childVerticalSpace, 0);
14 childHorizontalSpace = attributes.getDimensionPixelSize(R.styleable.GridImageViewGroup_childHorizontalSpace, 0);
15 columnNum = attributes.getInt(R.styleable.GridImageViewGroup_columnNum, 3);
16 attributes.recycle();
17 }
18 }
19
20 @Override
21 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
22 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
23 int rw = MeasureSpec.getSize(widthMeasureSpec);
24 int rh = MeasureSpec.getSize(heightMeasureSpec);
25 int childCount = getChildCount();
26 if (childCount > 0) {
27 childWidth = (rw – (columnNum – 1) * childHorizontalSpace) / columnNum;
28
29 childHeight = childWidth;
30
31 int vw = rw;
32 if (childCount < columnNum) {
33 vw = childCount * (childHeight + childVerticalSpace);
34 }
35 int rowCount = childCount / columnNum + (childCount % columnNum != 0 ? 1 : 0);
36
37 int vh = rowCount * childHeight + (rowCount > 0 ? rowCount – 1 : 0) * childVerticalSpace;
38
39 setMeasuredDimension(vw, vh);
40 }
41 }
42
43 @Override
44 protected void onLayout(boolean changed, int l, int t, int r, int b) {
45 int left = 0;
46 int top = 0;
47 int count = getChildCount();
48 for (int i = 0; i < count; i++) {
49 View child = getChildAt(i);
50 left = (i % columnNum) * (childWidth + childHorizontalSpace);
51 top = (i / columnNum) * (childHeight + childVerticalSpace);
52 child.layout(left, top, left + childWidth, top + childHeight);
53 }
54 }

在xml中引用:

1 <com.whoislcj.animation.GridImageViewGroup
2 android:id="@+id/image_layout"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:layout_margin="10dp"
6 android:animateLayoutChanges="true"
7 lee:childHorizontalSpace="10dp"
8 lee:childVerticalSpace="10dp"
9 lee:columnNum="3"/>

在Activity中调用:

1 private void initViews() {
2 mImageViewGroup = (GridImageViewGroup) findViewById(R.id.image_layout);
3 ImageView imageView = new ImageView(this);
4 imageView.setImageResource(R.mipmap.add_image);
5 imageView.setOnClickListener(new View.OnClickListener() {
6 @Override
7 public void onClick(View v) {
8 addImageView();
9 }
10 });
11 mImageViewGroup.addView(imageView);
12 }
13
14 public void addImageView() {
15 final ImageView imageView = new ImageView(MainActivity4.this);
16 imageView.setImageResource(R.mipmap.lottery);
17 imageView.setOnClickListener(new View.OnClickListener() {
18 @Override
19 public void onClick(View v) {
20 mImageViewGroup.removeView(imageView);
21 }
22 });
23 mImageViewGroup.addView(imageView, 0);
24 }

实现效果如下:

布局动画产生的背景:
     凡事总要问个明白,为何要引入布局动画呢?其实通过上面的实现效果可以看出,在添加和删除图片时都显得很突兀,不知道该用什么语言形容了,总之就是感觉不舒服。其实我平时在开发中调用View.setVisibility()方法时也会有这种感受,这也是布局动画产生的一个背景吧。
布局动画:
   布局动画是指ViewGroup在布局时产生的动画效果 。实现布局动画有如下几种方式
第一种方式:在xml中,对ViewGrope设置android:animateLayoutChanges="true"属性:

1 <com.whoislcj.animation.GridImageViewGroup
2 android:id="@+id/image_layout"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:layout_margin="10dp"
6 android:animateLayoutChanges="true"
7 lee:childHorizontalSpace="10dp"
8 lee:childVerticalSpace="10dp"
9 lee:columnNum="3"/>

就这么简单的一句话实现的效果就可以实现了,看看效果如何

这种方式虽然简单但是实现的布局动画比较单一,下面看第二种方式。
第二种方式:LayoutTransition实现

1 LayoutTransition mLayoutTransition = new LayoutTransition();
2
3 //设置每个动画持续的时间
4 mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 50);
5 mLayoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 50);
6 mLayoutTransition.setStagger(LayoutTransition.APPEARING, 50);
7 mLayoutTransition.setStagger(LayoutTransition.DISAPPEARING, 50);
8
9 PropertyValuesHolder appearingScaleX = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1.0f);
10 PropertyValuesHolder appearingScaleY = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 1.0f);
11 PropertyValuesHolder appearingAlpha = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
12 ObjectAnimator mAnimatorAppearing = ObjectAnimator.ofPropertyValuesHolder(this, appearingAlpha, appearingScaleX, appearingScaleY);
13 //为LayoutTransition设置动画及动画类型
14 mLayoutTransition.setAnimator(LayoutTransition.APPEARING, mAnimatorAppearing);
15
16
17 PropertyValuesHolder disappearingAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
18 PropertyValuesHolder disappearingRotationY = PropertyValuesHolder.ofFloat("rotationY", 0.0f, 90.0f);
19 ObjectAnimator mAnimatorDisappearing = ObjectAnimator.ofPropertyValuesHolder(this, disappearingAlpha, disappearingRotationY);
20 //为LayoutTransition设置动画及动画类型
21 mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mAnimatorDisappearing);
22
23
24 ObjectAnimator mAnimatorChangeDisappearing = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
25 //为LayoutTransition设置动画及动画类型
26 mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mAnimatorChangeDisappearing);
27
28 ObjectAnimator mAnimatorChangeAppearing = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
29 //为LayoutTransition设置动画及动画类型
30 mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, mAnimatorChangeAppearing);
31
32 //为mImageViewGroup设置mLayoutTransition对象
33 mImageViewGroup.setLayoutTransition(mLayoutTransition);

上面通过自定义LayoutTransition 修改系统提高的默认动画效果,如果不需要自定义的动画效果的话,不调用mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mAnimatorDisappearing);就行了。
LayoutTransition 提供了以下几种过渡类型:

APPEARING —— 元素在容器中显现时需要动画显示。
CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
DISAPPEARING —— 元素在容器中消失时需要动画显示。
CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。

看下修改过的动画效果:
 
第三种方式:通过设置LayoutAnimation来实现布局动画

1 AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
2 alphaAnimation.setDuration(200);
3 LayoutAnimationController animationController = new LayoutAnimationController(alphaAnimation, 0.5f);
4 animationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
5 mImageViewGroup.setLayoutAnimation(animationController);

 显示顺序有以下几种:

 ORDER_NORMAL;//顺序显示
 ORDER_REVERSE;//反显示
 ORDER_RANDOM//随机显示

也可以通过xml实现

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/alpha"
/>

ViewGroup xml添加android:layoutAnimation属性

<com.whoislcj.animation.GridImageViewGroup
android:id="@+id/image_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layoutAnimation="@anim/layoutanimation"
lee:childHorizontalSpace="10dp"
lee:childVerticalSpace="10dp"
lee:columnNum="3"/>

由于这种方式采用的是补间动画,个人不再推荐使用这种方式,原因很简单实现的动画效果相对单一。
总结:
   本篇学习了布局动画,自此Android的动画学习也将告一段落了,接下来准备总结一下学习动画的过程中遇见的编程知识,比如链式编程,TreadLocal等。

最后编辑:
作者:
这个作者貌似有点懒,什么都没有留下。

留下一个回复