Android 动画系列之属性(Property)动画详解
2016-07-30 19:39
465 查看
转载请标明出处: http://blog.csdn.net/airsaid/article/details/52074566
本文出自:周游的博客
前言
简介
Animator
ObjectAnimator
ValueAnimator
AnimatorSet
PropertyValuesHolder
动画监听
XML定义属性动画
XML中定义ObjectAnimator
XML中定义ValueAnimator
XML中定义AnimatorSet
总结
在前2篇的补间动画中我们知道了我们可以对一个View进行:缩放、旋转、平移、淡入淡出操作,并且可以做自定义补间动画的操作。但是自定义补间动画操作起来很麻烦,而自带的那几种使用起来虽然简单,但是也仅限于这几种了,补间动画的机制其实就是使用硬编码来完成的,功能已经限定死了,基本没有任何扩展性可言。还有就是如果我们使用补间动画使View往右移动一段距离,那么其实这个View依然还在原点,并没有真正移动,而使用属性动画移动到那个点就是在那个点。还有一个重要的点是,补间动画只能够作用在View上的,那么如果你想对其他非View对象进行动画操作,那就GG了。说了这么多,相信大家已经知道补间和属性动画的区别了。
属性动画其对应的类是Animator,和补间动画中的Animation一样,Animator也是一个抽象类,其对应的继承关系如下图:
* addListener(Animator.AnimatorListener listener):监听动画的开始、重复、和结束。
* addPauseListener(Animator.AnimatorPauseListener listener):为动画添加一个暂停监听。
* cancel() :取消动画
* clone():对动画进行拷贝。
* end():结束动画。
* getDuration():获取动画的持续时间。
* getInterpolator():获取动画的时间插补器。
* getListeners():获取监听器集合。
* getStartDelay():获取动画延迟开始的时间。
* isPaused():检查动画是否处于暂停状态。
* isRunning():检查动画是否正在运行(已经启动,并走过了startDelay(),尚未结束)
* isStarted():检查动画是否已经开始,没有结束。
* pause():暂停正在运动的动画。
* removeAllListeners():删除所有的listeners 与pauseListeners对象。
* removeListener(Animator.AnimatorListener listener):移除指定的AnimatorListener监听器。
* removePauseListener(Animator.AnimatorPauseListener listener):移除指定的AnimatorPauseListene监听器。
* resume():恢复已经暂停的动画。
* setDuration(long duration):设置动画持续时间。
* setInterpolator(TimeInterpolator value):设置时间插值器。
* setStartDelay(long startDelay):设置动画延迟多少毫秒后start()方法被调用。
* setTarget(Object target):设置目标对象。
* start():启动动画。
由于Animator是属性动画的基类,那么其子类也都有上面的方法。我们在具体使用中我们通常会使用它的子类,下面具体来看看子类的使用。
* 新建一个布局文件:
代码中实现点击事件开启了一个旋转动画:
运行结果:
可以看到,我们调用ofFloat(Object target, String propertyName, float… values) 构建ObjectAnimator时候,只传入了这个动画要操作的View,以及操作这个View的属性,还有就是可变参,就实现了一个动画。
那么问题来了,除了传入rotation属性之外,还可以传入啥属性呢?
其实在我们使用ObjectAnimator做动画的时候,并不是根据XML中定义的属性来改变的,而是去通过指定的属性去查找所对于的get、set方法来改变的。那我们上面的操作的ImageView有setRotation()方法么?答案是有的。都是通过View继承而来的。我们可以看看View中一共有哪些相关的方法:
知道了有哪些之后,我们可以继续来验证一下其他的动画。
平移动画:
运行结果:
* 透明动画:
运行结果:
* 缩放动画:
运行结果:
关于ObjectAnimator,我们只需知道一些简单的用法就行了,真正的重头戏在后面。
属性动画的运行机制是通过不断的对值进行操作来实现的,我们只需要把初始值和结束值给ValueAnimator,其内部会使用一种时间循环的机制来计算值与值之间的动画过渡,来自动帮我们完成从初始值到结束值的平滑过度效果。
首先来看看ValueAnimator的用法,其实和ObjectAnimator类似,只不过少了属性值的参数:
可以看到,其实同构ObjectAnimator对比,ValueAnimator通过of…构建对象的参数只有一个可变参,而没有了作用的View和属性名。
这是因为,ValueAnimator只提供了平滑过度的值,而你要用这个值做什么,完全由自己决定。
我们可以通过监听来打印看看ValueAnimator提供给我们的值:
打印结果:
通过ValueAnimator实现位移动画:
运行结果:
after(Animator anim) 将传入的动画在原有动画执行之前执行:
运行结果:
after(long delay) 将现有动画延迟指定毫秒后执行:
运行结果:
* before(Animator anim) 将插入的动画在原有动画执行之后执行:
运行结果:
* with(Animator anim) 将插入的动画和原有动画同时执行:
运行结果:
运行结果:
如果你只想监听动画的结束,而又觉得每次都得实现所有的接口很繁琐,那么你可以试试Andorid给我们提供的适配器类:AnimatorListenerAdapter
需要监听哪个事件,只需单独重写一下该方法就行了。
*
*
*
代码中使用:
运行结果:
代码中使用:
运行结果:
代码:
运行结果:
本文出自:周游的博客
前言
简介
Animator
ObjectAnimator
ValueAnimator
AnimatorSet
PropertyValuesHolder
动画监听
XML定义属性动画
XML中定义ObjectAnimator
XML中定义ValueAnimator
XML中定义AnimatorSet
总结
前言
前面博文中写了逐帧 和补间动画 的使用,今天有时间来继续写写属性动画。简介
众所周知,属性动画是Android3.0版本开始的,一个东西的推出肯定是有它的道理的,那为什么前面已经有逐帧和补间动画了还要推出属性动画呢?在前2篇的补间动画中我们知道了我们可以对一个View进行:缩放、旋转、平移、淡入淡出操作,并且可以做自定义补间动画的操作。但是自定义补间动画操作起来很麻烦,而自带的那几种使用起来虽然简单,但是也仅限于这几种了,补间动画的机制其实就是使用硬编码来完成的,功能已经限定死了,基本没有任何扩展性可言。还有就是如果我们使用补间动画使View往右移动一段距离,那么其实这个View依然还在原点,并没有真正移动,而使用属性动画移动到那个点就是在那个点。还有一个重要的点是,补间动画只能够作用在View上的,那么如果你想对其他非View对象进行动画操作,那就GG了。说了这么多,相信大家已经知道补间和属性动画的区别了。
属性动画其对应的类是Animator,和补间动画中的Animation一样,Animator也是一个抽象类,其对应的继承关系如下图:
Animator
Animator有如下方法:* addListener(Animator.AnimatorListener listener):监听动画的开始、重复、和结束。
* addPauseListener(Animator.AnimatorPauseListener listener):为动画添加一个暂停监听。
* cancel() :取消动画
* clone():对动画进行拷贝。
* end():结束动画。
* getDuration():获取动画的持续时间。
* getInterpolator():获取动画的时间插补器。
* getListeners():获取监听器集合。
* getStartDelay():获取动画延迟开始的时间。
* isPaused():检查动画是否处于暂停状态。
* isRunning():检查动画是否正在运行(已经启动,并走过了startDelay(),尚未结束)
* isStarted():检查动画是否已经开始,没有结束。
* pause():暂停正在运动的动画。
* removeAllListeners():删除所有的listeners 与pauseListeners对象。
* removeListener(Animator.AnimatorListener listener):移除指定的AnimatorListener监听器。
* removePauseListener(Animator.AnimatorPauseListener listener):移除指定的AnimatorPauseListene监听器。
* resume():恢复已经暂停的动画。
* setDuration(long duration):设置动画持续时间。
* setInterpolator(TimeInterpolator value):设置时间插值器。
* setStartDelay(long startDelay):设置动画延迟多少毫秒后start()方法被调用。
* setTarget(Object target):设置目标对象。
* start():启动动画。
由于Animator是属性动画的基类,那么其子类也都有上面的方法。我们在具体使用中我们通常会使用它的子类,下面具体来看看子类的使用。
ObjectAnimator
首先来用ObjectAnimator实现下补间动画中的操作。因为ObjectAnimator继承自ValueAnimator,使用起来是最简单的,分分钟实现一个动画:* 新建一个布局文件:
<?xml version="1.0" encoding="utf-8"?> <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" tools:context="com.airsaid.propertyanimationdemo.MainActivity"> <ImageView android:onClick="startAnim" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher"/> </RelativeLayout>
代码中实现点击事件开启了一个旋转动画:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startAnim(View v){ ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(v, "rotation", 0.0f, 360f); rotateAnim.setDuration(3000); rotateAnim.start(); } }
运行结果:
可以看到,我们调用ofFloat(Object target, String propertyName, float… values) 构建ObjectAnimator时候,只传入了这个动画要操作的View,以及操作这个View的属性,还有就是可变参,就实现了一个动画。
那么问题来了,除了传入rotation属性之外,还可以传入啥属性呢?
其实在我们使用ObjectAnimator做动画的时候,并不是根据XML中定义的属性来改变的,而是去通过指定的属性去查找所对于的get、set方法来改变的。那我们上面的操作的ImageView有setRotation()方法么?答案是有的。都是通过View继承而来的。我们可以看看View中一共有哪些相关的方法:
//1、透明度:alpha public void setAlpha(float alpha) //2、旋转度数:rotation、rotationX、rotationY public void setRotation(float rotation) public void setRotationX(float rotationX) public void setRotationY(float rotationY) //3、平移:translationX、translationY public void setTranslationX(float translationX) public void setTranslationY(float translationY) //缩放:scaleX、scaleY public void setScaleX(float scaleX) public void setScaleY(float scaleY)
知道了有哪些之后,我们可以继续来验证一下其他的动画。
平移动画:
ObjectAnimator moveAnim = ObjectAnimator.ofFloat(v, "translationX", v.getTranslationX(), -200.0f, v.getTranslationX()); moveAnim.setDuration(3000); moveAnim.start();
运行结果:
* 透明动画:
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 0.0f, 1.0f); alphaAnim.setDuration(3000); alphaAnim.start();
运行结果:
* 缩放动画:
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(v, "scaleX", 1.0f, 0.0f, 2.0f, 1.0f); scaleAnim .setDuration(3000); scaleAnim .start();
运行结果:
关于ObjectAnimator,我们只需知道一些简单的用法就行了,真正的重头戏在后面。
ValueAnimator
ValueAnimator直接继承自抽象类Animator,它是整个属性动画中最核心的一个类了,其实上面写到的ObjectAnimator就是对ValueAnimator的一个封装实现。可以让我们更方便的实现简单的动画效果。属性动画的运行机制是通过不断的对值进行操作来实现的,我们只需要把初始值和结束值给ValueAnimator,其内部会使用一种时间循环的机制来计算值与值之间的动画过渡,来自动帮我们完成从初始值到结束值的平滑过度效果。
首先来看看ValueAnimator的用法,其实和ObjectAnimator类似,只不过少了属性值的参数:
ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f); animator.setDuration(300); animator.start();
可以看到,其实同构ObjectAnimator对比,ValueAnimator通过of…构建对象的参数只有一个可变参,而没有了作用的View和属性名。
这是因为,ValueAnimator只提供了平滑过度的值,而你要用这个值做什么,完全由自己决定。
我们可以通过监听来打印看看ValueAnimator提供给我们的值:
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); Log.i("test", "value: " + value); } });
打印结果:
07-30 10:05:56.128 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 0.0 07-30 10:05:56.145 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 0.7902175 07-30 10:05:56.163 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 3.1359017 07-30 10:05:56.179 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 7.231784 07-30 10:05:56.200 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 12.494448 07-30 10:05:56.220 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 18.942606 07-30 10:05:56.232 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 26.372465 07-30 10:05:56.249 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 35.047955 07-30 10:05:56.266 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 43.733345 07-30 10:05:56.283 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 52.616795 07-30 10:05:56.300 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 61.417534 07-30 10:05:56.318 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 70.33683 07-30 10:05:56.335 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 78.10417 07-30 10:05:56.352 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 84.98317 07-30 10:05:56.369 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 90.756386 07-30 10:05:56.387 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 95.46181 07-30 10:05:56.404 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 98.42916 07-30 10:05:56.421 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 99.86572 07-30 10:05:56.438 25367-25367/com.airsaid.propertyanimationdemo I/test: value: 100.0
通过ValueAnimator实现位移动画:
ValueAnimator animator = ValueAnimator.ofFloat(0f, 100f, -100f, 0f); animator.setDuration(1000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); v.setTranslationY(value); } }); animator.start();
运行结果:
AnimatorSet
AnimatorSet用于实现组合动画,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:after(Animator anim) 将传入的动画在原有动画执行之前执行:
// 将after中传入的缩放动画在原有动画之前执行 ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(v, "rotation", 0.0f, 360f); ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(v, "scaleX", 1.0f, 0.0f, 2.0f, 1.0f); AnimatorSet animSet = new AnimatorSet(); animSet.play(rotateAnim).after(scaleAnim); animSet.setDuration(1000); animSet.start();
运行结果:
after(long delay) 将现有动画延迟指定毫秒后执行:
animSet.play(rotateAnim).after(1000);
运行结果:
* before(Animator anim) 将插入的动画在原有动画执行之后执行:
animSet.play(rotateAnim).before(scaleAnim);
运行结果:
* with(Animator anim) 将插入的动画和原有动画同时执行:
animSet.play(rotateAnim).with(scaleAnim);
运行结果:
PropertyValuesHolder
除了上面使用AnimatorSet实现了一组动画播放之外,我们还可以通过PropertyValuesHolder实现一组动画播放:PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY,pvhZ).setDuration(1000).start();
运行结果:
动画监听
Animator提供了一个动画监听的方法:addListener(),通过传入一个AnimatorListener来实现监听:rotateAnim.addListener(new Animator.AnimatorListener() { // 动画开始的时候调用 @Override public void onAnimationStart(Animator animation) { } // 动画结束的时候调用 @Override public void onAnimationEnd(Animator animation) { } // 动画被取消的时候调用 @Override public void onAnimationCancel(Animator animation) { } // 动画重复执行的时候调用 @Override public void onAnimationRepeat(Animator animation) { } });
如果你只想监听动画的结束,而又觉得每次都得实现所有的接口很繁琐,那么你可以试试Andorid给我们提供的适配器类:AnimatorListenerAdapter
rotateAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } });
需要监听哪个事件,只需单独重写一下该方法就行了。
XML定义属性动画
除了在代码中使用外,我们还可以在XML文件中定义属性动画。其中定义属性动画的XML资源文件能以如下三个元素中任意一个作为根元素:*
<set.../>:该元素定义的资源代表AnimatorSet对象,它是一个父元素,用于包含
<objectAnimator.../>、
<animator.../>或者
<set.../>子元素。
*
<objectAnimator.../>:用于定义ObjectAnimator动画。
*
<animator.../>:用于定义ValueAnimator动画。
XML中定义ObjectAnimator
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:propertyName="rotation" android:valueFrom="0.0f" android:valueTo="360.0f" android:valueType="floatType"/>
代码中使用:
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.anim_property); animator.setTarget(v); animator.start();
运行结果:
XML中定义ValueAnimator
<?xml version="1.0" encoding="utf-8"?> <animator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:valueFrom="0" android:valueTo="100" android:valueType="intType"/>
代码中使用:
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.anim_property); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int) animation.getAnimatedValue(); Log.i("test", "value: " + value); } }); animator.start();
运行结果:
XML中定义AnimatorSet
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:propertyName="rotation" android:valueFrom="0f" android:valueTo="360f" android:valueType="floatType"/> <objectAnimator android:propertyName="alpha" android:valueFrom="0.0f" android:valueTo="1.0f" android:valueType="floatType"/> </set>
代码:
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.anim_property); animator.setDuration(300); animator.setTarget(v); animator.start();
运行结果:
总结
合理的将动画结合到我们的项目中,会使我们的应用更加的酷炫。相关文章推荐
- android adb命令
- Android 开发之布局细节对比:RTL模式
- Android第二周(第三部分)-GridView和ScrollView
- android 绘图之Paint详解
- Android 表情面板的展示和表情的显示
- Android 中使用Coding代码管理 初级教程
- Android自定义侧滑菜单栏代码实现
- openCV 人脸检测在 Android 中的应用
- Android加载动画系列——WifiLoadingAnim
- Android记忆之我的开始
- Android中ListView的优化点笔记
- Android 整合实现简单易用、功能强大的RecyclerView
- Android广告图片轮播控件,支持无限循环和5种主题,可以灵活设置轮播样式、时间、位置、图片加载框架等!
- Android加载动画系列—— LineWithTextLoadingAnim
- Android中用intent启动另一个activity
- [Android] 如何查看apk需要支持的Android版本
- 全网最强Android开发/源码资源汇总,倾力打造,绝对精品!!
- 自定义View新手实战-一步步实现精美的钟表界面
- Android加载动画系列——CircularZoomLoadingAnim
- android中简单的信息存储