转载请注明出处:http://blog.csdn.net/yegongheng/article/details/38435553
上一篇博文我们初步地了解了Property Animation的工作方式及流程,并通过实验加深了对对象属性计算过程的理解,同时,我在文章的最后罗列一些实现Property Animation比较重要的类、接口和方法,并做了比较详细地说明。那今天这篇文章,我将带领大家使用这些Android系统提供的API来实现一些比较炫的动画效果。
ValueAnimator是Property Animation系统的核心类,它包含了配置Property Animation属性的大部分方法,那要实现一个Property Animation,都需要直接或间接使用ValueAnimator类。那接下来我们将借助ValueAnimator类提供的方法来实现各种各样的动画效果,不过在此之前我们来学习一下实现动画的几个关键知识点。
public class CustomInterpolator implements TimeInterpolator { @Override public float getInterpolation(float input) { // 编写相关的逻辑计算 //input *= 0.8f; return input * input; } }上面是一个简单的示例,我们要实现一个自定义的Interpolator,只需在方法中编写相关的罗就计算就行。
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实现动画分为以下七个步骤:
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实现图片缩放动画 */ 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设置目标对象并启动动画。我们运行一下程序,看一下运行的效果图,如下:
/** * 隐藏或显示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。运行程序,动画效果如下:
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(); } }
<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>代码量有些多,不过每个方法都有注释,而且逻辑也比较简单,所以不难理解,只要读者花点时间研究一下就可以很好的掌握。那接下来我们运行程序,运行及操作效果图如下:
源代码下载,请戳下面: