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

Android中编写属性动画PropertyAnimation的进阶实例

程序员文章站 2024-02-28 14:00:46
0、基础回顾 propertyanimation,属性动画,顾名思义就是利用对象的属性变化形成动画的效果。属性动画的类可以用animator这个抽象类来表示,通常使用它的...

0、基础回顾
propertyanimation,属性动画,顾名思义就是利用对象的属性变化形成动画的效果。属性动画的类可以用animator这个抽象类来表示,通常使用它的子类:animatorset和valueanimator,同时valueanimator有两个子类分别是objectaniamtor和timeanimator。
定义属性动画的xml资源的时候通常可以是如下三个元素之一作为根元素:
<set>元素:该资源元素代表的是aniamtorset类,这个类可以包含<set>,<objectaniamtor>,<animator>三个子元素。
<objectanimator>元素:用于定义objectaniamtor类。
<animator>元素:用于定义valueanimator类。
比如说这里一个资源文件的定义如下:

<set android:ordering="[together|sequentially]">
 
  <objectanimator
 
      android:propertyname="string"
      android:duration="int"
      android:valuefrom="float|int|color"
      android:valueto="float|int|color"
      android:startoffset="int"
      android:repeatcount="int"
      android:interpolator=""
      android:repeatmode="[reapeat|reverse]"
      android:valuetype="[inttype|floattype]"/>
  
  <animator 
      
      android:duration="int"
      android:valuefrom="float|int|color"
      android:valueto="float|int|color"
      android:startoffset="int"
      android:repeatcount="int"
      android:interpolator=""
      android:repeatmode="[reapeat|reverse]"
      android:valuetype="[inttype|floattype]"/>
 
  <set>
    ....
  </set>
 
</set>

属性文件通常保存在animator文件夹下面。

1、如何使用xml文件来创建属性动画
大家肯定都清楚,view animator 、drawable animator都可以在anim文件夹下创建动画,然后在程序中使用,甚至在theme中设置为属性值。当然了,属性动画其实也可以在文件中声明:
首先在res下建立animator文件夹,然后建立res/animator/scalex.xml

<?xml version="1.0" encoding="utf-8"?> 
<objectanimator xmlns:android="http://schemas.android.com/apk/res/android" 
  android:duration="1000" 
  android:propertyname="scalex" 
  android:valuefrom="1.0" 
  android:valueto="2.0" 
  android:valuetype="floattype" > 
</objectanimator> 

代码:

public void scalex(view view) 
  { 
    // 加载动画 
    animator anim = animatorinflater.loadanimator(this, r.animator.scalex); 
    anim.settarget(mmv); 
    anim.start(); 
  } 

使用animatorinflater加载动画的资源文件,然后设置目标,就ok~~是不是很简单,这只是单纯横向的放大一倍~
如果我希望纵向与横向同时缩放呢?则可以怎么定义属性文件:

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android" 
  android:ordering="together" > 
 
  <objectanimator 
    android:duration="1000" 
    android:propertyname="scalex" 
    android:valuefrom="1" 
    android:valueto="0.5" > 
  </objectanimator> 
  <objectanimator 
    android:duration="1000" 
    android:propertyname="scaley" 
    android:valuefrom="1" 
    android:valueto="0.5" > 
  </objectanimator> 
 
</set> 

使用set标签,有一个orderring属性设置为together,【还有另一个值:sequentially(表示一个接一个执行)】。
上篇博客中忽略了一个效果,就是缩放、反转等都有中心点或者轴,默认中心缩放,和中间对称线为反转线,所以我决定这个横向,纵向缩小以左上角为中心点:
代码:

// 加载动画 
    animator anim = animatorinflater.loadanimator(this, r.animator.scale); 
    mmv.setpivotx(0); 
    mmv.setpivoty(0); 
    //显示的调用invalidate 
    mmv.invalidate(); 
    anim.settarget(mmv); 
    anim.start(); 

很简单,直接给view设置pivotx和pivoty,然后调用一下invalidate,就ok了。
下面看效果图:

Android中编写属性动画PropertyAnimation的进阶实例

好了,通过写xml声明动画,使用set嵌套set,结合orderring属性,也基本可以实现任何动画~~上面也演示了pivot的设置。

2、布局动画(layout animations)
主要使用layouttransition为布局的容器设置动画,当容器中的视图层次发生变化时存在过渡的动画效果。
基本代码为:

layouttransition transition = new layouttransition(); 
  transition.setanimator(layouttransition.change_appearing, 
      transition.getanimator(layouttransition.change_appearing)); 
  transition.setanimator(layouttransition.appearing, 
      null); 
  transition.setanimator(layouttransition.disappearing, 
      null); 
  transition.setanimator(layouttransition.change_disappearing, 
      null); 
  mgridlayout.setlayouttransition(transition); 

过渡的类型一共有四种:
(1)layouttransition.appearing 当一个view在viewgroup中出现时,对此view设置的动画
(2)layouttransition.change_appearing 当一个view在viewgroup中出现时,对此view对其他view位置造成影响,对其他view设置的动画
(3)layouttransition.disappearing  当一个view在viewgroup中消失时,对此view设置的动画
(4)layouttransition.change_disappearing 当一个view在viewgroup中消失时,对此view对其他view位置造成影响,对其他view设置的动画
(5)layouttransition.change 不是由于view出现或消失造成对其他view位置造成影响,然后对其他view设置的动画。
注意动画到底设置在谁身上,此view还是其他view。
好了下面看一个综合的例子:
布局文件:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:id="@+id/id_container" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:orientation="vertical" > 
 
  <button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:onclick="addbtn" 
    android:text="addbtns" /> 
 
  <checkbox 
    android:id="@+id/id_appear" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:checked="true" 
    android:text="appearing" /> 
 
  <checkbox 
    android:id="@+id/id_change_appear" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:checked="true" 
    android:text="change_appearing" /> 
 
  <checkbox 
    android:id="@+id/id_disappear" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:checked="true" 
    android:text="disappearing" /> 
 
  <checkbox 
     android:id="@+id/id_change_disappear" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:checked="true" 
    android:text="change_disappearing " /> 
 
</linearlayout> 

代码:

package com.example.zhy_property_animation; 
 
import android.animation.layouttransition; 
import android.app.activity; 
import android.os.bundle; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.view.viewgroup; 
import android.widget.button; 
import android.widget.checkbox; 
import android.widget.compoundbutton; 
import android.widget.compoundbutton.oncheckedchangelistener; 
import android.widget.gridlayout; 
 
public class layoutanimaactivity extends activity implements 
    oncheckedchangelistener 
{ 
  private viewgroup viewgroup; 
  private gridlayout mgridlayout; 
  private int mval; 
  private layouttransition mtransition; 
 
  private checkbox mappear, mchangeappear, mdisappear, mchangedisappear; 
 
  @override 
  public void oncreate(bundle savedinstancestate) 
  { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.layout_animator); 
    viewgroup = (viewgroup) findviewbyid(r.id.id_container); 
 
    mappear = (checkbox) findviewbyid(r.id.id_appear); 
    mchangeappear = (checkbox) findviewbyid(r.id.id_change_appear); 
    mdisappear = (checkbox) findviewbyid(r.id.id_disappear); 
    mchangedisappear = (checkbox) findviewbyid(r.id.id_change_disappear); 
 
    mappear.setoncheckedchangelistener(this); 
    mchangeappear.setoncheckedchangelistener(this); 
    mdisappear.setoncheckedchangelistener(this); 
    mchangedisappear.setoncheckedchangelistener(this); 
 
    // 创建一个gridlayout 
    mgridlayout = new gridlayout(this); 
    // 设置每列5个按钮 
    mgridlayout.setcolumncount(5); 
    // 添加到布局中 
    viewgroup.addview(mgridlayout); 
    //默认动画全部开启 
    mtransition = new layouttransition(); 
    mgridlayout.setlayouttransition(mtransition); 
 
  } 
 
  /** 
   * 添加按钮 
   * 
   * @param view 
   */ 
  public void addbtn(view view) 
  { 
    final button button = new button(this); 
    button.settext((++mval) + ""); 
    mgridlayout.addview(button, math.min(1, mgridlayout.getchildcount())); 
    button.setonclicklistener(new onclicklistener() 
    { 
 
      @override 
      public void onclick(view v) 
      { 
        mgridlayout.removeview(button); 
      } 
    }); 
  } 
 
  @override 
  public void oncheckedchanged(compoundbutton buttonview, boolean ischecked) 
  { 
    mtransition = new layouttransition(); 
    mtransition.setanimator( 
        layouttransition.appearing, 
        (mappear.ischecked() ? mtransition 
            .getanimator(layouttransition.appearing) : null)); 
    mtransition 
        .setanimator( 
            layouttransition.change_appearing, 
            (mchangeappear.ischecked() ? mtransition 
                .getanimator(layouttransition.change_appearing) 
                : null)); 
    mtransition.setanimator( 
        layouttransition.disappearing, 
        (mdisappear.ischecked() ? mtransition 
            .getanimator(layouttransition.disappearing) : null)); 
    mtransition.setanimator( 
        layouttransition.change_disappearing, 
        (mchangedisappear.ischecked() ? mtransition 
            .getanimator(layouttransition.change_disappearing) 
            : null)); 
    mgridlayout.setlayouttransition(mtransition); 
  } 
} 

效果图:

Android中编写属性动画PropertyAnimation的进阶实例

动画有点长,耐心点看,一定要注意,是对当前view还是其他views设置的动画。
当然了动画支持自定义,还支持设置时间,比如我们修改下,添加的动画为:

mtransition.setanimator(layouttransition.appearing, (mappear 
        .ischecked() ? objectanimator.offloat(this, "scalex", 0, 1) 
        : null)); 

则效果为:

Android中编写属性动画PropertyAnimation的进阶实例

原本的淡入,变成了宽度从中间放大的效果~~是不是还不错~~

3、view的anim方法
在sdk11的时候,给view添加了animate方法,更加方便的实现动画效果。
布局文件:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent"  
  > 
 
  <imageview 
    android:id="@+id/id_ball" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/bol_blue" /> 
 
  <linearlayout 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignparentbottom="true" 
    android:orientation="horizontal" > 
 
    <button 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:onclick="viewanim" 
      android:text="view anim" /> 
 
    <button 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:onclick="propertyvaluesholder" 
      android:text="propertyvaluesholder " /> 
     
 
  </linearlayout> 
 
</relativelayout> 

代码:

package com.example.zhy_property_animation; 
 
import android.animation.objectanimator; 
import android.animation.propertyvaluesholder; 
import android.app.activity; 
import android.os.bundle; 
import android.util.displaymetrics; 
import android.util.log; 
import android.view.view; 
import android.widget.imageview; 
 
public class viewanimateactivity extends activity 
{ 
  protected static final string tag = "viewanimateactivity"; 
 
  private imageview mblueball; 
  private float mscreenheight; 
 
  @override 
  protected void oncreate(bundle savedinstancestate) 
  { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.view_animator); 
 
    displaymetrics outmetrics = new displaymetrics(); 
    getwindowmanager().getdefaultdisplay().getmetrics(outmetrics); 
    mscreenheight = outmetrics.heightpixels; 
    mblueball = (imageview) findviewbyid(r.id.id_ball); 
 
  } 
 
  public void viewanim(view view) 
  { 
    // need api12 
    mblueball.animate()// 
        .alpha(0)// 
        .y(mscreenheight / 2).setduration(1000) 
        // need api 12 
        .withstartaction(new runnable() 
        { 
          @override 
          public void run() 
          { 
            log.e(tag, "start"); 
          } 
          // need api 16 
        }).withendaction(new runnable() 
        { 
 
          @override 
          public void run() 
          { 
            log.e(tag, "end"); 
            runonuithread(new runnable() 
            { 
              @override 
              public void run() 
              { 
                mblueball.sety(0); 
                mblueball.setalpha(1.0f); 
              } 
            }); 
          } 
        }).start(); 
  }  
}         

                                                                                                       

简单的使用mblueball.animate().alpha(0).y(mscreenheight / 2).setduration(1000).start()就能实现动画~~不过需要sdk11,此后在sdk12,sdk16又分别添加了withstartaction和withendaction用于在动画前,和动画后执行一些操作。当然也可以.setlistener(listener)等操作。
使用objectanimator实现上面的变化,我们可以使用:propertyvalueholder

propertyvaluesholder pvhx = propertyvaluesholder.offloat("alpha", 1f, 
      0f, 1f); 
  propertyvaluesholder pvhy = propertyvaluesholder.offloat("y", 0, 
      mscreenheight / 2, 0); 
  objectanimator.ofpropertyvaluesholder(mblueball, pvhx, pvhy).setduration(1000).start(); 

效果与上面一样。
运行结果:

Android中编写属性动画PropertyAnimation的进阶实例