您的位置:首页 > 移动开发 > Objective-C

Android动画学习(三)之使用ValueAnimator和ObjectAnimator实现动画实例

2014-08-08 10:26 886 查看
转载请注明出处/article/7809137.html

上一篇博文我们初步地了解了Property Animation的工作方式及流程,并通过实验加深了对对象属性计算过程的理解,同时,我在文章的最后罗列一些实现Property Animation比较重要的类、接口和方法,并做了比较详细地说明。那今天这篇文章,我将带领大家使用这些Android系统提供的API来实现一些比较炫的动画效果。

使用ValueAnimator实现动画

ValueAnimator是Property Animation系统的核心类,它包含了配置Property Animation属性的大部分方法,那要实现一个Property Animation,都需要直接或间接使用ValueAnimator类。那接下来我们将借助ValueAnimator类提供的方法来实现各种各样的动画效果,不过在此之前我们来学习一下实现动画的几个关键知识点。

Animator监听器介绍

Property Animation提供了Animator.AnimatorListener和Animator.AnimatorUpdateListener两个监听器用于动画在播放过程中的重要动画事件。下面是两个监听器接口和方法的一些介绍和说明:
Animator.AnimatorListener:

onAnimationStart() —— 动画开始时调用;
onAnimationEnd() —— 动画结束时调用;
onAnimationRepeat() —— 动画循环播放时调用;
onAnimationCancel() —— 动画被取消时调用。不管终止的方式如何,被取消的动画仍然会调onAnimationEnd();
Animator.AnimatorUpdateListener:

onAnimationUpdate() —— 动画每播放一帧时调用。在动画过程中,可侦听此事件来获取并使用 ValueAnimator 计算出来的属性值。利用传入事件的 ValueAnimator 对象,调用其 getAnimatedValue() 方法即可获取当前的属性值。如果使用 ValueAnimator来实现动画的话 ,则必需实现此侦听器。

使用及自定义Interpolator

关于Interpolator(插值器)的知识,我们在上一篇博文就有接触,在这里再做详细介绍:插值器它定义了动画变化过程中的属性变化规则,它根据时间比例因子计算出一个插值因子,用于设定目标对象的动画执行是否为线性变化、非线性变化或先加速后减速等等。Android系统本身内置了一些通用的Interpolator(插值器),如下:



我们可以使用以上系统提供的插值器对目标对象实现一些诸如先加速后加速、弹跳和回移的动画效果。那如果以上这些插值器都无法满足我们的具体开发需求的话,那么也可以通过继承TimeInterpolator类来自定义自己的Interpolator,在自定义的Interpolator类中只需要要重写getInterpolation(float input)方法,并在该方法通过相关的计算,再返回计算后的结果(插值因子)就搞定,具体示例如下:

public class CustomInterpolator implements TimeInterpolator {

@Override
public float getInterpolation(float input) {
// 编写相关的逻辑计算
//input *= 0.8f;
return input * input;
}
}
上面是一个简单的示例,我们要实现一个自定义的Interpolator,只需在方法中编写相关的罗就计算就行。

使用及自定义TypeEvaluator

上面学习了如何自定义Interpolator计算返回插值因子,那下一步就是使用TypeEvaluator根据插值因子计算属性值,Android系统可识别的类型包括int、float和颜色,分别由 IntEvaluator、 FloatEvaluator、 ArgbEvaluator 提供支持,如下:



同样的,如何系统提供的TypeEvaluator不能满足我们的要求,我们也可以通过继承TypeEvaluator类来定义自己的Evaluator,在自定义的TypeEvaluator类中只需要要重写getInterpolation(float input)方法,并在该方法通过相关的计算,再返回计算后的结果(插值因子)就搞定,具体示例如下:
import android.animation.TypeEvaluator;
import android.annotation.SuppressLint;

@SuppressLint("NewApi")
public class CustomEvaluator implements TypeEvaluator<Number> {

@Override
public Float evaluate(float fraction, Number startValue, Number endValue) {
// TODO Auto-generated method stub
float propertyResult = 0;
/*float startFloat = startValue.floatValue();
return (startFloat + fraction * (endValue.floatValue() - startFloat));*/
return propertyResult;
}
}

使用ValueAnimator实现动画的步骤及实践

那一般使用ValueAnimator实现动画分为以下七个步骤:

1. 调用ValueAnimation类中的ofInt(int...values)、ofFloat(String propertyName,float...values)等静态方法实例化ValueAnimator对象,并设置目标属性的属性名、初始值或结束值等值;

2.调用addUpdateListener(AnimatorUpdateListener mListener)方法为ValueAnimator对象设置属性变化的监听器;

3.创建自定义的Interpolator,调用setInterpolator(TimeInterpolator value)为ValueAniamtor设置自定义的Interpolator;(可选,不设置默认为缺省值)

4.创建自定义的TypeEvaluator,调用setEvaluator(TypeEvaluator value)为ValueAnimator设置自定义的TypeEvaluator;(可选,不设置默认为缺省值)

5.在AnimatorUpdateListener 中的实现方法为目标对象的属性设置计算好的属性值。

6.设置动画的持续时间、是否重复及重复次数等属性;

7.为ValueAnimator设置目标对象并开始执行动画。

接下来我们将按照以上步骤实现我们的动画。首先开始第一个例子:就是放置在屏幕中的一张图片,通过不断地改变该图片相对于左边屏幕的距离,从而实现图片左右滑动的动画的效果。下面贴出实现动画的关键代码:
/**
* 使用ValueAnimator改变Imageview的margin的值
*/
public void marginValueAnimator(){
//1.调用ofInt(int...values)方法创建ValueAnimator对象
ValueAnimator mAnimator = ValueAnimator.ofInt(0,screenWidth - mImageViewTest.getWidth());
//2.为目标对象的属性变化设置监听器
mAnimator.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 3.为目标对象的属性设置计算好的属性值
int animatorValue = (int)animation.getAnimatedValue();
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mImageViewTest.getLayoutParams();
marginLayoutParams.leftMargin = animatorValue;
mImageViewTest.setLayoutParams(marginLayoutParams);
}
});
//4.设置动画的持续时间、是否重复及重复次数等属性
mAnimator.setDuration(2000);
mAnimator.setRepeatCount(3);
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
//5.为ValueAnimator设置目标对象并开始执行动画
mAnimator.setTarget(mImageViewTest);
mAnimator.start();
}
上面代码中,我们将属性的初始值、结束值分为设置为0和(屏幕宽度-ImageView控件的宽度),然后在监听方法中,通过调用getAnimationValue()获取动画在播放过程中属性值的变化情况,然后将属性值赋给ImageView对象的marginLeft。接着调用setXX()方法设置动画的相关属性,最后调用start()方法,执行动画。动画的实现流程和我们基本按照我们上面罗列的步骤基本一致,只不过没有设置Interpolator和TypeEvaluator,系统会自动默认为缺省。ImageView的实例化代码和screenWidth屏幕宽度的获取代码在此不列出,具体的代码在文章末尾可以提供下载。
简单讲解了一下代码后,我们下面来看看运行的效果图:



观察上面的运行效果图,我们成功实现了图片左右滑动的效果。
下面我们接着使用ValueAnimator实现图片的缩放效果的功能,先来看一下具体实现的代码,如下:
/**
* 使用ValueAnimator实现图片缩放动画
*/
public void scaleValueAnimator(){
//1.设置目标属性名及属性变化的初始值和结束值
PropertyValuesHolder mPropertyValuesHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f,0.0f);
PropertyValuesHolder mPropertyValuesHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f,0.0f);
ValueAnimator mAnimator = ValueAnimator.ofPropertyValuesHolder(mPropertyValuesHolderScaleX,mPropertyValuesHolderScaleY);
//2.为目标对象的属性变化设置监听器
mAnimator.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 3.根据属性名获取属性变化的值分别为ImageView目标对象设置X和Y轴的缩放值
float animatorValueScaleX =  (float) animation.getAnimatedValue("scaleX");
float animatorValueScaleY = (float) animation.getAnimatedValue("scaleY");
mImageViewTest.setScaleX(animatorValueScaleX);
mImageViewTest.setScaleY(animatorValueScaleY);

}
});
//4.为ValueAnimator设置自定义的Interpolator
mAnimator.setInterpolator(new CustomInterpolator());
//5.设置动画的持续时间、是否重复及重复次数等属性
mAnimator.setDuration(2000);
mAnimator.setRepeatCount(3);
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
//6.为ValueAnimator设置目标对象并开始执行动画
mAnimator.setTarget(mImageViewTest);
mAnimator.start();
}
上面代码列表中,我们通过PropertyValuesHolder类为目标属性名来设置属性值的初始值和结束值,然后ValueAnimator通过调用ofPropertyValuesHolder(PropertyValuesHolder...values)设置已经配置好的PropertyValuesHolder对象。不过需要注意的是使用PropertyValuesHolder设置的属性必须是目标对象的属性中有setXX()方法才能进行设置,例如ImageView对象中有setScaleX()方法才能为ImageView设置对应属性的PropertyValuesHolder对象。接着ValueAnimator对象调用setInterpolator(TimeInterpolator
value)设置自定义的Interpolator,类名为CustomInterpolator,具体的代码如下:
package com.androidleaf.animation.customproperty;

import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;

@SuppressLint("NewApi")
public class CustomInterpolator implements TimeInterpolator {

@Override
public float getInterpolation(float input) {
input *= 0.8f;
return input * input;
}
}
接着,为ValueAnimator对象设置相应的属性,如动画重复次数、动画所持续的时间等等。最后,为ValueAnimator设置目标对象并启动动画。我们运行一下程序,看一下运行的效果图,如下:



观察上面的运行效果图,我们可以发现图片不仅实现了收缩动画,而且还实现了一个迅速的收缩和回弹的效果,原因是我们通过自定义Interpolator,使得ScaleX和ScaleY属性值的变化呈非线性的变化,那涉及到自定义Interpolator的知识在上面我们已经学习过了,在此就不重复讲解了。

最后我们再来使用ValueAnimator实现一个比较实用的动画效果,就是通过动态改变一个ListView列表的高,来动态显示或隐藏ListView。我们先来看一下关键代码,如下:
/**
* 隐藏或显示ListView的动画
*/
public void hideOrShowListViewAnimator(final int startValue,final int endValue){
//1.设置属性的初始值和结束值
ValueAnimator mAnimator = ValueAnimator.ofInt(0,100);
//2.为目标对象的属性变化设置监听器
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
int animatorValue = (int)animation.getAnimatedValue();
float fraction = animatorValue/100f;
IntEvaluator mEvaluator = new IntEvaluator();
//3.使用IntEvaluator计算属性值并赋值给ListView的高
mListView.getLayoutParams().height = mEvaluator.evaluate(fraction, startValue, endValue);
mListView.requestLayout();
}
});
//4.为ValueAnimator设置LinearInterpolator
mAnimator.setInterpolator(new LinearInterpolator());
//5.设置动画的持续时间
mAnimator.setDuration(500);
//6.为ValueAnimator设置目标对象并开始执行动画
mAnimator.setTarget(mListView);
mAnimator.start();
}
上面代码列表中,需传递的两个参数分别为属性值的初始值和结束值,当需要显示ListView时,传入0和800像素值,当需要隐藏ListView时,传入800和0像素值,ListView的初始化高度默认是0。运行程序,动画效果如下:



ValueAnimator的相关知识就讲到这里,想要做出更炫更实用的动画,读者可自行深入研究ValueAniamator类的实现和原理。

使用ObjectAnimator实现动画

我们接着学习一个比较重要的动画实现类--ObjectAnimator。该类作为ValueAnimator的子类不仅继承了ValueAnimator的所有方法和特性,并且还封装很多实用的方法,方便开发人员快速实现动画。同时,由于属性值会自动更新,使用ObjectAnimator实现动画不需要像ValueAnimator那样必须实现 ValueAnimator.AnimatorUpdateListener
,因此实现任意对象的动画显示就更加容易了。我们在大部分的开发工作中,都会使用ObjectAnimator而非ValueAnimator实现我们所需的动画效果。
前几篇博文我们都介绍了View Animation,我们了解了其实现View对象动画的特点,即View Animation本身是通过改变View的绘制方式来实现动画的,View对象本身的属性值并没有改变,对象仍然停留在原始位置。那Android为了消除这一弊病,在 Android 3.0 中给 View 增加了一些新的属性以及相应的 getter、setter 方法。Property
Animation系统可以通过修改 View 对象实际的属性值来实现屏幕上的动画效果。此外,当属性值发生变化时,Views 也会自动调用 invalidate() 方法来刷新屏幕。 View 类中新增的便于实现 property 动画的属性包括:
(1) translationX 和 translationY:这两个属性控制着 View 的屏幕位置坐标变化量,以 layout 容器的左上角为坐标原点;

(2) rotation、rotationX 和 rotationY:这三个属性控制着 2D 旋转角度(rotation属性)和围绕某枢轴点的 3D 旋转角度;

(3) scaleX、scaleY:这两个属性控制着 View 围绕某枢轴点的 2D 缩放比例;

(4) pivotX 和 pivotY: 这两个属性控制着枢轴点的位置,前述的旋转和缩放都是以此点为中心展开的,缺省的枢轴点是 View 对象的中心点;

(5) x 和 y:这是指 View 在容器内的最终位置,等于 View 左上角相对于容器的坐标加上 translationX 和 translationY 后的值;

(6)alpha:表示 View 的 alpha 透明度。缺省值为 1 (不透明),为 0 则表示完全透明(看不见);

要动画显示 View 对象的某个属性,比如颜色或旋转值,我们所有要做的事情就是创建一个 Property animation,并设定对应的 View 属性。那接下来我们就用ObjectAnimator类来分别实现View的透明度渐变、收缩、移动和旋转等动画效果,那在此之前我们也来总结下使用ObjectAnimator实现动画的几个步骤,如下:
1.通过调用ofFloat()、ofInt()等方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值;
2.设置动画的持续时间、是否重复及重复次数等属性;
3.启动动画。
我们发现使用ObjectAnimator实现动画比ValueAnimator更加简单和方便,下面分别是我们实例中使用ObjectAnimator实现透明度渐变、伸缩、移动和旋转的代码(具体代码在文章末尾提供下),如下:
public class ObjectAnimatorFragment extends Fragment implements OnClickListener{

private ListView mListViewFront;
private ListView mListViewReverse;
private Button mButtonFlip;
private Button mButtonAlpha;
private Button mButtonScale;
private Button mButtonTranslate;
private Button mButtonRotate;
private Button mButtonSet;
private ImageView mImageView;

private int screenWidth = 0;
private int screenHeight = 0;

String[] frontStrs = {
"Front Page 1",
"Front Page 2",
"Front Page 3",
"Front Page 4",
"Front Page 5",
"Front Page 6",
};

String[] reverseStrs = {
"Reverse Page 1",
"Reverse Page 2",
"Reverse Page 3",
"Reverse Page 4",
"Reverse Page 5",
"Reverse Page 6",
};
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
//screenWidth = (int)(metrics.widthPixels * density + 0.5f);
//screenHeight = (int)(metrics.heightPixels * density + 0.5f);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.fragment_objectanimator, container, false);
mListViewFront = (ListView) rootView.findViewById(R.id.front_page_listview);
mListViewReverse = (ListView) rootView.findViewById(R.id.reverse_page_listview);
mButtonFlip = (Button)rootView.findViewById(R.id.button_flip);
mButtonFlip.setOnClickListener(this);
mButtonAlpha = (Button)rootView.findViewById(R.id.button_alpha);
mButtonAlpha.setOnClickListener(this);
mButtonScale = (Button)rootView.findViewById(R.id.button_scale);
mButtonScale.setOnClickListener(this);
mButtonTranslate = (Button)rootView.findViewById(R.id.button_translate);
mButtonTranslate.setOnClickListener(this);
mButtonRotate = (Button)rootView.findViewById(R.id.button_rotate);
mButtonRotate.setOnClickListener(this);
mButtonSet = (Button)rootView.findViewById(R.id.button_set);
mButtonSet.setOnClickListener(this);
mImageView = (ImageView)rootView.findViewById(R.id.objectanimator_imageview);
mImageView.setOnClickListener(this);
initData();
return rootView;
}

public void initData(){
ArrayAdapter<String> frontListData = new ArrayAdapter<String>(getActivity(), R.layout.layout_objectanimator_item,R.id.objectanimtor_item_textview, frontStrs);
ArrayAdapter<String> reverseListData = new ArrayAdapter<String>(getActivity(), R.layout.layout_objectanimator_item,R.id.objectanimtor_item_textview, reverseStrs);

mListViewFront.setAdapter(frontListData);
mListViewReverse.setAdapter(reverseListData);
mListViewReverse.setRotationX(-90.0f);

}
@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();

}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.button_flip:
flip();
break;
case R.id.button_alpha:
alphaAnimator();
break;
case R.id.button_scale:
scaleAnimator();
break;
case R.id.button_translate:
translateAniamtor();
break;
case R.id.button_rotate:
rotateAniamtor();
break;
case R.id.button_set:
setAnimator();
break;
case R.id.objectanimator_imageview:
mListViewFront.setVisibility(View.VISIBLE);
mImageView.setVisibility(View.GONE);
break;
default:
break;
}
}

/**
* 翻转动画效果
*/
public void flip(){
final ListView visibleView;
final ListView invisibleView;
if(mListViewFront.getVisibility() == View.GONE){
visibleView = mListViewReverse;
invisibleView = mListViewFront;
}else{
visibleView = mListViewFront;
invisibleView = mListViewReverse;
}
//创建ListView从Visible到Gone的动画
ObjectAnimator visibleToInVisable = ObjectAnimator.ofFloat(visibleView, "rotationX", 0.0f,90.0f);
//设置插值器
visibleToInVisable.setInterpolator(new AccelerateInterpolator());
visibleToInVisable.setDuration(500);

//创建ListView从Gone到Visible的动画
final ObjectAnimator invisibleToVisible = ObjectAnimator.ofFloat(invisibleView, "rotationX", -90.0f,0.0f);
//设置插值器
invisibleToVisible.setInterpolator(new DecelerateInterpolator());
invisibleToVisible.setDuration(500);

visibleToInVisable.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
visibleView.setVisibility(View.GONE);
invisibleToVisible.start();
invisibleView.setVisibility(View.VISIBLE);
}
});
visibleToInVisable.start();
}

/**
* 渐变动画效果
*/
public void alphaAnimator(){
ListView alphaListView = null;
if(mListViewFront.getVisibility() == View.GONE){
alphaListView = mListViewReverse;
}else{
alphaListView = mListViewFront;
}
//1、通过调用ofFloat()方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值;
ObjectAnimator mAnimatorAlpha = ObjectAnimator.ofFloat(alphaListView, "alpha", 1.0f,0.0f);
//2、设置动画的持续时间、是否重复及重复次数属性;
mAnimatorAlpha.setRepeatMode(Animation.REVERSE);
mAnimatorAlpha.setRepeatCount(3);
mAnimatorAlpha.setDuration(1000);
//3、启动动画
mAnimatorAlpha.start();
}

/**
* 伸缩动画效果
*/
public void scaleAnimator(){
ListView scaleListView = null;
if(mListViewFront.getVisibility() == View.GONE){
scaleListView = mListViewReverse;
}else{
scaleListView = mListViewFront;
}

ObjectAnimator mAnimatorScaleX = ObjectAnimator.ofFloat(scaleListView, "scaleX", 1.0f,0.0f);
mAnimatorScaleX.setRepeatMode(Animation.REVERSE);
mAnimatorScaleX.setRepeatCount(3);
mAnimatorScaleX.setDuration(1000);

ObjectAnimator mAnimatorScaleY = ObjectAnimator.ofFloat(scaleListView, "scaleY", 1.0f,0.0f);
mAnimatorScaleY.setRepeatMode(Animation.REVERSE);
mAnimatorScaleY.setRepeatCount(3);
mAnimatorScaleY.setDuration(1000);

mAnimatorScaleX.start();
mAnimatorScaleY.start();
}

/**
* 位移动画效果
*/
public void translateAniamtor(){
ListView translateListView = null;
if(mListViewFront.getVisibility() == View.GONE){
translateListView = mListViewReverse;
}else{
translateListView = mListViewFront;
}

ObjectAnimator mAnimatorTranslateX = ObjectAnimator.ofFloat(translateListView, "translationX", 0.0f,screenWidth/2);
mAnimatorTranslateX.setRepeatMode(Animation.REVERSE);
mAnimatorTranslateX.setRepeatCount(3);
mAnimatorTranslateX.setDuration(1000);

ObjectAnimator mAnimatorTranslateY = ObjectAnimator.ofFloat(translateListView, "translationY", 0.0f,screenHeight/2);
mAnimatorTranslateY.setRepeatMode(Animation.REVERSE);
mAnimatorTranslateY.setRepeatCount(3);
mAnimatorTranslateY.setDuration(1000);

mAnimatorTranslateX.start();
mAnimatorTranslateY.start();
}

/**
* 旋转动画效果
*/
public void rotateAniamtor(){
ListView rotateListView = null;
if(mListViewFront.getVisibility() == View.GONE){
rotateListView = mListViewReverse;
}else{
rotateListView = mListViewFront;
}
ObjectAnimator mAnimatorRotate = ObjectAnimator.ofFloat(rotateListView, "rotation", 0.0f,360.0f);
mAnimatorRotate.setRepeatMode(Animation.REVERSE);
mAnimatorRotate.setRepeatCount(2);
mAnimatorRotate.setDuration(2000);

mAnimatorRotate.start();
}
/**
* 动画集合
*/
public void setAnimator(){
ListView setListView = null;
if(mListViewFront.getVisibility() == View.GONE){
setListView = mListViewReverse;
}else{
setListView = mListViewFront;
}
setListView.setVisibility(View.GONE);
if(mImageView.getVisibility() == View.GONE){
mImageView.setVisibility(View.VISIBLE);
}
//代码方式设置动画
codeAnimatorSet(mImageView);

//用ViewPropertyAnimator实现动画
//viewPropertyAnimator(setListView);

//加载XML文件中的动画
/*AnimatorSet mAnimatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(getActivity(), R.animator.property_animation_animatorset);
mAnimatorSet.setTarget(mImageView);
mAnimatorSet.start();*/
}

/**
* 使用编码方式实现动画效果
* @param mImageView
*/
public void codeAnimatorSet(ImageView mImageView){
AnimatorSet mAnimatorSet = new AnimatorSet();

ObjectAnimator mAnimatorSetRotateX = ObjectAnimator.ofFloat(mImageView, "rotationX", 0.0f,360.0f);
mAnimatorSetRotateX.setDuration(3000);

ObjectAnimator mAnimatorSetRotateY = ObjectAnimator.ofFloat(mImageView, "rotationY", 0.0f,360.0f);
mAnimatorSetRotateY.setDuration(3000);

ObjectAnimator mAnimatorScaleX = ObjectAnimator.ofFloat(mImageView, "scaleX", 1.0f,0.5f);
mAnimatorScaleX.setRepeatCount(1);
mAnimatorScaleX.setRepeatMode(Animation.REVERSE);
mAnimatorScaleX.setDuration(1500);

ObjectAnimator mAnimatorScaleY = ObjectAnimator.ofFloat(mImageView, "scaleY", 1.0f,0.5f);
mAnimatorScaleY.setRepeatCount(1);
mAnimatorScaleY.setRepeatMode(Animation.REVERSE);
mAnimatorScaleY.setDuration(1500);

mAnimatorSet.play(mAnimatorSetRotateY).with(mAnimatorScaleX);
mAnimatorSet.play(mAnimatorScaleX).with(mAnimatorScaleY);
mAnimatorSet.play(mAnimatorSetRotateY).before(mAnimatorSetRotateX);

mAnimatorSet.start();
}

public void viewPropertyAnimator(ListView mListViewHolder){
mListViewHolder.animate().cancel();
mListViewHolder.animate().rotationX(360.0f).setDuration(3000).start();
}

}


Fragment的布局界面代码如下:
<LinearLayout 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"
android:orientation="vertical"
android:background="@color/view_animation_background"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="翻转"
android:id="@+id/button_flip"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Alpha"
android:id="@+id/button_alpha"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scale"
android:id="@+id/button_scale"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Translate"
android:id="@+id/button_translate"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rotate"
android:id="@+id/button_rotate"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Set"
android:id="@+id/button_set"
/>
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/propertyanimator_background"
android:dividerHeight="0.5dp"
android:id="@+id/front_page_listview"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/propertyanimator_background"
android:visibility="gone"
android:dividerHeight="0.5dp"
android:id="@+id/reverse_page_listview"
/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitStart"
android:visibility="visible"
android:src="@drawable/liduohai"
android:id="@+id/objectanimator_imageview"
/>
</LinearLayout>
代码量有些多,不过每个方法都有注释,而且逻辑也比较简单,所以不难理解,只要读者花点时间研究一下就可以很好的掌握。那接下来我们运行程序,运行及操作效果图如下:
(1)ListView翻转、渐变透明、伸缩、移动和旋转动画效果:(2)图片翻转集合动画效果:





上面的动画效果很炫吧,不过呢使用ObjectAnimator实现动画也有一些要求和限制,一般有以下几点需要注意:
1.动画显示的属性必须带有一个 setter 方法(以骆驼拼写法命名),格式类似 set<propertyName>()。 因为 ObjectAnimator 会在动画期间自动更新属性值,它必须能够用此 setter 方法访问到该属性。 例如:假设属性名称为foo,则需要有一个setFoo()方法。 而你如果此 setter 方法不存在,那么我们可以有以下三种选择:

<1>如果权限允许的话,直接在类中增加此 setter 方法;

<2>修改封装类来增加此 setter 方法,并让该封装类来接收属性值并传给初始的对象;

<3>换用 ValueAnimator。

2.如果在调用 ObjectAnimator 的某个工厂方法时,我们只为 values... 参数指定了一个值,那此值将被认定为动画属性的结束值。 这样的话,动画显示的属性必须带有一个 getter 方法,用于获取动画的起始值。 此 getter 方法必须以get<propertyName>()的格式命名。 例如:假设属性名为foo,则需要有一个getFoo()方法。

3.动画属性的 getter 方法(如果必要的话)和 setter 方法所操作数据的类型必须与 ObjectAnimator 中设定的起始和结束值相同。

小结:今天我们主要了解了ValueAnimator和ObjectAnimator的概念及其它们关系和特点,并通过实例学习了如何使用这两个类实现了非常炫的动画效果。总结一下本文我们需要掌握的知识点:(1)了解并学会使用动画监听器;(2)了解Interpolator的概念及作用,并学会自定义Interpolator;(3)解TypeEvaluator的概念及作用,并学会自定义TypeEvaluator;(4)熟练使用ValueAnimator实现动画;(5)熟练使用ObjectAnimator实现动画;(6)使用ObjectAnimator实现动画的一些限制和需要注意的事项。由于篇幅关系,我们下一章还会学习如何为ViewGroup中的Layout设置动画效果,敬请期待!

源代码下载,请戳下面:

GITHUB下载
CSDN下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐