欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-07 21:15:15
前言: 前面几篇文章介绍了补间动画、逐帧动画、属性动画,大部分都是针对view来实现的动画,那么该如何为了一个viewgroup添加动画呢?今天结合自定义viewgr...

前言:

前面几篇文章介绍了补间动画、逐帧动画、属性动画,大部分都是针对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);
 }

实现效果如下: 

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

布局动画产生的背景:

凡事总要问个明白,为何要引入布局动画呢?其实通过上面的实现效果可以看出,在添加和删除图片时都显得很突兀,不知道该用什么语言形容了,总之就是感觉不舒服。其实我平时在开发中调用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"/>

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

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

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

第二种方式: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 —— 由于容器中某个元素要消失,其它元素的变化需要动画显示。 

看下修改过的动画效果: 

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

第三种方式:通过设置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等。