Android动画效果之自定义ViewGroup添加布局动画(五)

前言:

前面几篇文章介绍了补间动画、逐帧动画、属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画。本文将通过对自定义图片选择控件设置动画为例来学习布局动画。

自定义一个显示多行图片的ViewGroup:

这里不再对自定义控件做解说,想了解的可以看下以下几篇文章
 •Android自定义控件之基本原理(一)
 •Android自定义控件之自定义属性(二)
 •Android自定义控件之自定义组合控件(三)
 •Android自定义控件之自定义ViewGroup实现标签云(四)

声明几个属性值:

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

GridImageViewGroup.java 代码

public class GridImageViewGroup extends ViewGroup {
 private int childVerticalSpace = 0;
 private int childHorizontalSpace = 0;
 private int columnNum = 3;
 private int childWidth = 0;
 private int childHeight = 0;

 public GridImageViewGroup(Context context, AttributeSet attrs) {
  super(context, attrs);
  TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.GridImageViewGroup);
  if (attributes != null) {
   childVerticalSpace = attributes.getDimensionPixelSize(R.styleable.GridImageViewGroup_childVerticalSpace, 0);
   childHorizontalSpace = attributes.getDimensionPixelSize(R.styleable.GridImageViewGroup_childHorizontalSpace, 0);
   columnNum = attributes.getInt(R.styleable.GridImageViewGroup_columnNum, 3);
   attributes.recycle();
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int rw = MeasureSpec.getSize(widthMeasureSpec);
  int rh = MeasureSpec.getSize(heightMeasureSpec);
  int childCount = getChildCount();
  if (childCount > 0) {
   childWidth = (rw - (columnNum - 1) * childHorizontalSpace) / columnNum;

   childHeight = childWidth;

   int vw = rw;
   if (childCount < columnNum) {
    vw = childCount * (childHeight + childVerticalSpace);
   }
   int rowCount = childCount / columnNum + (childCount % columnNum != 0 ? 1 : 0);

   int vh = rowCount * childHeight + (rowCount > 0 ? rowCount - 1 : 0) * childVerticalSpace;

   setMeasuredDimension(vw, vh);
  }
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  int left = 0;
  int top = 0;
  int count = getChildCount();
  for (int i = 0; i < count; i++) {
   View child = getChildAt(i);
   left = (i % columnNum) * (childWidth + childHorizontalSpace);
   top = (i / columnNum) * (childHeight + childVerticalSpace);
   child.layout(left, top, left + childWidth, top + childHeight);
  }
 }

在xml中引用:

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

在Activity中调用:

private void initViews() {
  mImageViewGroup = (GridImageViewGroup) findViewById(R.id.image_layout);
  ImageView imageView = new ImageView(this);
  imageView.setImageResource(R.mipmap.add_image);
  imageView.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    addImageView();
   }
  });
  mImageViewGroup.addView(imageView);
 }

 public void addImageView() {
  final ImageView imageView = new ImageView(MainActivity4.this);
  imageView.setImageResource(R.mipmap.lottery);
  imageView.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    mImageViewGroup.removeView(imageView);
   }
  });
  mImageViewGroup.addView(imageView, 0);
 }

实现效果如下:

布局动画产生的背景:

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

布局动画:

布局动画是指ViewGroup在布局时产生的动画效果 。实现布局动画有如下几种方式 
第一种方式:在xml中,对ViewGrope设置android:animateLayoutChanges="true"属性:

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

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

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

第二种方式:LayoutTransition实现

 LayoutTransition mLayoutTransition = new LayoutTransition();

  //设置每个动画持续的时间
  mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, 50);
  mLayoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 50);
  mLayoutTransition.setStagger(LayoutTransition.APPEARING, 50);
  mLayoutTransition.setStagger(LayoutTransition.DISAPPEARING, 50);

  PropertyValuesHolder appearingScaleX = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1.0f);
  PropertyValuesHolder appearingScaleY = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 1.0f);
  PropertyValuesHolder appearingAlpha = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
  ObjectAnimator mAnimatorAppearing = ObjectAnimator.ofPropertyValuesHolder(this, appearingAlpha, appearingScaleX, appearingScaleY);
  //为LayoutTransition设置动画及动画类型
  mLayoutTransition.setAnimator(LayoutTransition.APPEARING, mAnimatorAppearing);

  PropertyValuesHolder disappearingAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
  PropertyValuesHolder disappearingRotationY = PropertyValuesHolder.ofFloat("rotationY", 0.0f, 90.0f);
  ObjectAnimator mAnimatorDisappearing = ObjectAnimator.ofPropertyValuesHolder(this, disappearingAlpha, disappearingRotationY);
  //为LayoutTransition设置动画及动画类型
  mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mAnimatorDisappearing);

  ObjectAnimator mAnimatorChangeDisappearing = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
  //为LayoutTransition设置动画及动画类型
  mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mAnimatorChangeDisappearing);

  ObjectAnimator mAnimatorChangeAppearing = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
  //为LayoutTransition设置动画及动画类型
  mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, mAnimatorChangeAppearing);

  //为mImageViewGroup设置mLayoutTransition对象
  mImageViewGroup.setLayoutTransition(mLayoutTransition);

上面通过自定义LayoutTransition 修改系统提高的默认动画效果,如果不需要自定义的动画效果的话,不调用mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mAnimatorDisappearing);就行了。 
LayoutTransition 提供了以下几种过渡类型:
 •APPEARING —— 元素在容器中显现时需要动画显示。
 •CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它元素的变化需要动画显示。
 •DISAPPEARING —— 元素在容器中消失时需要动画显示。
 •CHANGE_DISAPPEARING —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。

看下修改过的动画效果:

第三种方式:通过设置LayoutAnimation来实现布局动画

 AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
  alphaAnimation.setDuration(200);
  LayoutAnimationController animationController = new LayoutAnimationController(alphaAnimation, 0.5f);
  animationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
  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等。

(0)

相关推荐

  • Android App开发中自定义View和ViewGroup的实例教程

    View Android所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top表示View相对于它的parent View的起点,width,height表示View自己的宽高,通过这4个字段就能确定View在屏幕上的位置,确定位置后就可以开始绘制View的内容了. View绘制过程 View的绘制可以分为下面三个过程: Measure View会先做一次测量,算出自己需要占用多大的面积.View的Measure过程给我们暴露了一个

  • Android自定义ViewGroup实现带箭头的圆角矩形菜单

    本文和大家一起做一个带箭头的圆角矩形菜单,大概长下面这个样子: 要求顶上的箭头要对准菜单锚点,菜单项按压反色,菜单背景色和按压色可配置. 最简单的做法就是让UX给个三角形的图片往上一贴,但是转念一想这样是不是太low了点,而且不同分辨率也不太好适配,干脆自定义一个ViewGroup吧! 自定义ViewGroup其实很简单,基本都是按一定的套路来的. 一.定义一个attrs.xml 就是声明一下你的这个自定义View有哪些可配置的属性,将来使用的时候可以自由配置.这里声明了7个属性,分别是:箭头宽

  • Android自定义ViewGroup之实现FlowLayout流式布局

    整理总结自鸿洋的博客:http://blog.csdn.net/lmj623565791/article/details/38352503/  一.FlowLayout介绍  所谓FlowLayout,就是控件根据ViewGroup的宽,自动的往右添加,如果当前行剩余空间不足,则自动添加到下一行.有点像所有的控件都往左飘的感觉,第一行满了,往第二行飘~所以也叫流式布局.Android并没有提供流式布局,但是某些场合中,流式布局还是非常适合使用的,比如关键字标签,搜索热词列表等,比如下图: git

  • Android自定义ViewGroup实现可滚动的横向布局(2)

    上一篇文章自定义viewgroup(1)地址:http://www.jb51.net/article/100608.htm 这里直接代码: package com.example.libingyuan.horizontallistview.ScrollViewGroup; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android

  • Android自定义ViewGroup打造各种风格的SlidingMenu

    上篇给大家介绍QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!! 用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接

  • 从源码解析Android中View的容器ViewGroup

    这回我们是深入到ViewGroup内部\,了解ViewGroup的工作,同时会阐述更多有关于View的相关知识.以便为以后能灵活的使用自定义空间打更近一步的基础.希望有志同道合的朋友一起来探讨,深入Android内部,深入理解Android. 一.ViewGroup是什么?        一个ViewGroup是一个可以包含子View的容器,是布局文件和View容器的基类.在这个类里定义了ViewGroup.LayoutParams类,这个类是布局参数的子类. 其实ViewGroup也就是Vie

  • Android应用开发中自定义ViewGroup的究极攻略

    支持margin,gravity以及水平,垂直排列 最近在学习android的view部分,于是动手实现了一个类似ViewPager的可上下或者左右拖动的ViewGroup,中间遇到了一些问题(例如touchEvent在onInterceptTouchEvent和onTouchEvent之间的传递流程),现在将我的实现过程记录下来. 首先,要实现一个ViewGroup,必须至少重写onLayout()方法(当然还有构造方法啦:)).onLayout()主要是用来安排子View在我们这个ViewG

  • Android自定义ViewGroup实现标签浮动效果

    前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup.目前实现的可以动态添加标签.可点击.效果图如下: 1.思路  首先在onMeasure方法中测量ViewGroup的宽和高,重点是处理当我们自定义的ViewGroup设置为wrap_content的情况下,如何去测量其大小的问题.当我们自定义的ViewGroup设置为wrap_content时,我们需要让子View先去测量自

  • Android编程重写ViewGroup实现卡片布局的方法

    本文实例讲述了Android编程重写ViewGroup实现卡片布局的方法.分享给大家供大家参考,具体如下: 实现效果如图: 实现思路 1. 重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)设置每个子View的大小 2. 重写onLayout(boolean changed, int l, int t, int r, int b) 设置每个子View的位置 第一步:新建FlowLayout继承ViewGroup package com

  • Android自定义ViewGroup的实现方法

    在android中提供了常见的几种ViewGroup的实现,包括LinearLayout.Relativeayout.FrameLayout等.这些ViewGroup可以满足我们一般的开发需求,但是对于界面要求复杂的,这几个布局就显得捉襟见肘了.所以自定义的ViewGroup在我们接触过的应用中比比皆是. 要想实现一个自定义的ViewGroup,第一步是学会自定义属性,这些自定义的属性将让我们配置布局文件的时候更加的灵活.自定义属性是在value目录下声明一个attrs.xml文件. <?xml

随机推荐