自定义控件——属性动画进阶

1.PropertyValuesHolder与KeyFrame
在前一节我们了解了ofInt(),ofFloat(),ofObject()函数的用法。ValueAnimator和ObjectAnimator创建Animator实例除此之外还有ofProperValuesHolder()

//ValueAnimator
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder ... 
values) 

//ObjectAnimator
public static ObjectAnimator ofPropertyValuesHolder(Object target, 
PropertyValuesHolder .. . values)

1.1 PropertyValuseHolder
PropertyValuesHolder类的含义就是,他其中保存了动画过程中所需要操作的属性和对应的值,在使用ofFloat(Object o,String propertyName,float … values)构造的动画,ofFloat()函数内部就是通过PropertyValuesHolder实例来保存动画状态的。在封装成PropertyValuesHolder实例之后,后期的各种操作就是以PropertyValuesHolder为主的。OnjectAnimator通过暴露PropertyValuesHolder的方法,向我们提供了一个口子,让我们可以通过PropertyValuesHolder来构造动画。
创建PropertyValuesHolder的实例函数如下:

public static PropertyValuesHolder ofFloat(String propertyName , float ... 
values) 
public static PropertyValuesHolder ofint (String propertyName , int .. va l ues ) 
public static PropertyValuesHolder ofObject(String propertyName , 
TypeEvaluator evaluator, Object ... values) 
public static PropertyValuesHolder ofKeyframe (String propertyName , Keyframe ... 
values)

在上面的ofInt(),ofFolat()中,propertyName表示ObjectAnimator需要操作的属性名。
values表示属性所对应的参数,为可边长参数。当只指定了参数时,ObjectAnimator会通过查找对应属性的getProperty()函数来获得初始值。与ObjectAnimator中的ofInt()相比较,只是少了一个target,在PropertyValuesHolder中的ofInt(),ofFloat()中创建的是PropertyValuesHolder对象,接下来是如何将PropertyValyesHolder实例设置到ObjectAnimator中。

1.1.1 ObjectAnimator.ofpropertyValuesHolder()
我们知道ObjectAnimator给我们提供了一个设置PropertyValuesHolder实例的入口

public static ObjectAnimator ofPropertyValuesHolder(Object target, 
PropertyValuesHolder .. . values)

target需要执行动画的控件
values可变长参数,可传入多个PropertyValuesHolder实例,由于每个PripertyValuesHolder实例都会针对一个属性执行动画操作,所以如果传入多个PropertyValuesHolder实例,则会对控件的多个属性同时执行动画操作。

1.1.2 PropertyValuesHolder之Object
ofObject()的构造函数

publc static PropertyValuesHolder ofObject (String propertyName , 
TypeEvaluator evaluator, Object . .. values)

propertyName——ObjectAnimator动画操作的属性名
evaluator——Evaluator实例
values——可变长参数,表示操作动画的属性的值

与ObjectAnimator.ofObject()函数的参数类似,只是少了一个target。

1.2 Keyframe
在看插值器,Evaluator时我们知道可以用来控制动画的速率,但是遇到较复杂的速率变化时,要涉及很复杂的数学知识,所以google提供了这样一个Keyframe类——关键帧,关键帧这个概念来源于动画,对于动画而言,一秒需要24帧图片,但是对于制作动画的人来说,并不是要把每一帧都画出来。比如,我们要让一只球在 30 秒内从(0,0 )点运动到(300,200)点在Flash 中,我们只需要定义两个关键帧, 在动画开始 定义1个关键帧,把球的位置设定在30秒后再定义一个关键帧,把球的位置设在(300,200)在动画开始时球位于(0,0)点,在 30 秒内 Adobe Flash就会自动填充,把球平滑移动到第二个关键帧的位置, 即(300,200) 点。
所以一个关键帧必须包含两个元素:时间点和位置
所以Keyframe的生成方式如下:

public static Keyframe ofFloat(float fraction , float value)

fraction表示当前的显示进度
value表示动画所在的数值位置
Keyframe ofFloat(0,0) 表示动画进度为0,动画所在数值位置为0;

1.2.1 PropertyValuesHolder是如何使用Keyframe对象的

public static PropertyValuesHolder ofKeyframe (String propertyName , Keyframe ... 
values)//属性名,keyfrane列表

KeyFrame的使用:
第一步 生成 Keyframe对象
第二步 利用 PropertyValuesHoIder.ofKeyframe() 函数生成 PropertyValuesHold对象
第三步 利用 ObjectAnimator.ofpropertyValuesHold () 函数生成对应Animator
示例:

Keyframe frameO = Keyframe . ofFloat (0f,0); 
Keyframe framel = Keyframe ofFloat(0.1f,-20f);
Keyframe frame2 = Keyframe ofFloat(1,0);
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation ",
frame0 , framel , frame2 ); 
Animator ani mator = ObjectAnmator.ofPropertyValuesHolder(mimage frameHolder)
animator setDurat on(1000)
aηimator start();

1.2.2 ofFloat与ofInt
构造函数:

//ofFloat
public static Keyframe ofFloat(float fraction);
public static Keyframe ofFloat(float fraction,float value);

//ofInt
public static Keyframe ofInt(float fraction);
public static Keyframe ofInt(float fraction,int value);

两个函数的参数类型是一样的
fraction表示当前关键帧所在动画进度位置
value表示当前位置所对应的值

1.2.3 插值器
Keyframe允许我们在Keyframe动作期间设置插值器:
public void setInterpolator(TimeInteropolator interpolator)
如果给当前这个Keyframe设置了插值器,那么从上一个Keyframe到当前Keyframe就是使用了这个插值器来进行计算的。
在没有设置插值器的情况下一般时使用的LinearInterpolator线性插值器。

1.2.4 Keyframe之ofObject
ofObject的构造函数:

public static Keyframe ofObject(float fraction) 
public static Keyframe ofObect(float fraction ,float value)

它的使用方法和ofInt,ofFloat差不多
但是在使用ofObject函数来制作动画的时候,必须调用frameHolder.setEvaluator函数显式设置Evaluetor,因为系统根本无法知道动画的中间值Object真正是什么类型。

1.2.5 关键帧的使用情况:

  • 如果去掉第0帧,会以第一帧为起始位置
  • 去掉结束帧,会以最后一帧为结束帧
  • 只保留一个中间帧,会在动画开始的时候就直接崩溃

1.2.6 PropertyValuesHolder之其他函数
除了ofInt(),ofFloat(),ofObject(),ofKeyframe()函数之外还有很多函数

//设置动画的Evaluetor
public void setEvaluator(TypeEvaluator evaluator)
//设置ofFloat所对应的动画值列表
public void setFloatValues(float ...values)
//设置ofInt所对应的动画值列表
public void setIntValues(float ...values)
//设置ofKeyframe所对应的动画值列表
public void setKeyframeValues(float ...values)
//设置ofObject所对应的动画值列表
public void setObjectValues(float ...values)
//设置动画属性名
public void setPropertyName(String propertyName)

1.3 ViewPropertyAnimator
ViewPropertyAnimator为android控件提供了更加易懂,更加便捷的,更加面向对象的API,是我们操作控件更简单。
例如:
textView.animate().alpha(0f);//将textView变为透明
tv.animate().x(100).y(100);//将控件移动到(100,100)

  • animate——整个系统从调用View的这个animate()的新函数开始。这个函数会返回一个ViewPropertyAnimator对象,可以通过这个对象的函数来设置需要实现动画的属性。
  • 自动开始,不需要我们显式的调用start函数。
  • 流畅,ViewPropertyAnimator拥有一个非常流畅的接口,它允许将多个函数调用很自然的串在一起,并把多属性的动画写成一行代码。

1.3.1 常用函数
自定义控件——属性动画进阶_第1张图片
1.3.2 设置监听器
ViewPropertyAnimator并非派生自Animator,但它允许我们设置Animator.AnimatorListener监听器。用法如下:

tv.animate().scaleX(2).scaleY(1).setListener(new Aniamtor.AnimatorListener(){
		public void onAnimationStart(Animator animator){

		}
		public void onAnimationRepeat(Animator animator){

		}
		public void onAnimationEnd(Animator animator){

		}
		public void onAnimationCancel(Animator animator){

		}

});

1.4 为ViewGroup内的组件添加动画
ViewAnimator,ObjectAnimator,AnimatorSet都只可以针对一个控件作动画,而无法对ViewGroup内的组件添加动画。
为此android提供了4中方法来解决这个问题

  • LayoutAnimation标签与LayoutAniamtionController——专门针对listView添加入场动画,可以实现listView创建时对其中的每个item添加入场动画,而且动画是可以自定义的。但是在listview创建完成后,如果再添加数据,则新数据是不会有入场动画的。
  • gridLayoutAnimation标签与GridLayoutAnimationController——专门针对gridView添加入场动画,可以实现gridView创建时对其中的每个item添加入场动画,而且动画是可以自定义的。但是在gridview创建完成后,如果再添加数据,则新数据是不会有入场动画的。
  • android:animateLayoutChanges属性——在API11之后,android为了支持ViewGroup类控件,在添加和移除其中的控件时自动添加动画,提供的一个非常简单的属性,android:animateLayoutChanges=“true/false”,所有派生自ViewGroup的控件都具有这个属性,在xml中添加这个属性就可以实现在添加/删除其中控件时带有默认的动画,但是不能实现自定义动画
  • LayoutTransition——可以实现在ViewGroup动态添加或者删除其中的控件时指定动画。动画可以是自定义的。

由于前三种的缺陷,在这里主要理解第四种LayoutTransition
使用方法:
第一步:创建实例

LayoutTransition transition= new LayoutTransition();

第二步:创建动画并进行设置

ObjectAnimator animator=ObjectAnimator.ofFloat(null,"rotation",0f,90f,0f);
transition.setAnimator(LayoutTransition.DISAPPEARING,animOut);

第三步:将LayoutTransition设置到ViewGroup中

LinearLayout.setLayoutTransition(transition);

第二步和第三步用到的函数如下:

public void setLayoutTransition(LayoutTransition transition)

public void setAnimator(int transitionType,Animator animator)
//当transitionType为APPEARING——元素在容器中出现时所定义的动画
//DISAPPEARING——元素在容器中消失所定义的动画
//CHANGE_APPARING——由于容器中要显示一个新的元素,其他需要变化的元素所应用的动画
//CHANGE_DUSAPPEARING——当容器中某个元素消失时,其他需要变化的元素所应用的动画

1.5 开源动画库NineOldAndroids
NIneOldAndroids中是没有LayoutTransition类的,其他都有
1.5.1 NineOldAndroids中的ViewpropertyAnimator
在这里不同的主要是ViewPropertyAnimator中的animate方法,在官方API3.1以上animate是自动开始动画的,但是在NineOldAndroids中是静态使用的,需要有start启动。

1.5.2 NineOldAndroids中的ViewHelper
ViewHelper提供了一系列的静态set/get方法去操作View的各种属性。

public static float getAlpha(View view) 
public static void setAlpha (View view float alpha) 
public static void setPivotX(View view float pivotX) 
publc static float getP votX(View view) 
public static void setPivotY(View view, float pivotY) 
public static float getPivotY(View view) 
public static void setRotation(View riew float rotatio日)
public static float getRotation(View ew)
public static void setRotationX(View riew float rotat onX)
public static float getRotationX(View view )
....

ViewHelper与属性动画一样,也是通过改变控件的自由属性来改变控件的个项值。所以移动后的控件在新位置也是可以响应点击事件的。

你可能感兴趣的:(读书笔记)