android开发艺术探索(七)
2016-08-30 09:48
441 查看
Android动画深入分析
Android动画可以分为三种:View动画、帧动画、属性动画。View动画
View动画的作用对象是View,它支持四种动画效果,分别是平移动画(TranslateAnimation)、缩放动画(ScaleAnimation)、旋转动画(RotateAnimation)、和透明度动画(AlphaAcnimation)。除此之外,还提供了动画集合AnimationSet动画集合,混合使用多种动画。
使用动画方式:
1、代码中加载xml动画文件。我们再res/anim文件夹下新建view_alpha.xml文件。
<?xml version="1.0" encoding="utf-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:fromAlpha="0" android:toAlpha="1" > </alpha>
在代码中加载此动画:
AlphaAnimation alpha= (AlphaAnimation) AnimationUtils.loadAnimation(MainActivity.this,R.anim.view_alpha); //设置动画持续时间 alpha.setDuration(1000); //View动画开始 ivPhoto.startAnimation(alpha);
2、在代码中构建动画
/**透明度动画,第一个参数为起始透明度 * 第二个参数为结束时透明度 * */ AlphaAnimation alpha=new AlphaAnimation(0,1); //设置动画持续时间 alpha.setDuration(1000); //View动画开始 ivPhoto.startAnimation(alpha);
我们先简单看一下动画的固定语法:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="true" android:duration="1000" android:fillAfter="true" > <alpha android:fromAlpha="0" android:toAlpha="1"></alpha> <scale android:fromXScale="0.5" android:fromYScale="0.5" android:pivotX="0" android:pivotY="0" android:toXScale="1.5" android:toYScale="1.5"></scale> <translate android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100" android:toYDelta="0"></translate> <rotate android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="225"></rotate> </set>
set标签,对应AnimationSet类,表示动画合集。
interpolator:表示动画集合所采用的插值器,插值器影响动画的速度。
shareInterpolator:表示动画集合是否共享同一个插值器。
duration:表示动画的持续时间。
fillAfter:动画结束后,View是否停留在结束位置,true表示View停留在结束位置,false则不停留。
translate标签:对应TranslateAnimation类,它可以使一个view在水平和竖直方向完成平移的动画效果。
fromXDelta:平移初始位置的x值
fromYDelta:平移初始位置的y值
toXDelta:平移结束位置的x值。
toYDelta:平移结束位置的y值。
scale标签:对应ScaleAnimation类,他可以使View具有放大或者缩小的动画效果。
fromXScale:水平方向缩放的起始值。
toXScale:水平方向缩放的结束值。
fromYScale:竖直方向缩放的起始值。
toYScale:竖直方向缩放的结束值。
pivotX:缩放的轴点x坐标,它会影响缩放的效果。
pivotY:缩放的轴点y坐标,会影响缩放的效果。
默认情况下,缩放的轴点是View的中心点
rotate:旋转动画,对应RotateAnimation,它可以使View具有旋转的动画效果。
fromDegrees:旋转开始的角度。
toDegrees:旋转结束的角度。
pivotX:旋转的轴点的x坐标。
pivotY:旋转的轴点的y坐标。
alpha:透明度动画,对应AlphaAnimation,可以改变View的透明度。
fromAlpha:表示透明度的起始值。
toAlpha:表示透明度的结束值。
代码生成:
1、透明度动画
/**透明度动画,第一个参数为起始透明度 * 第二个参数为结束时透明度 * */ AlphaAnimation alpha=new AlphaAnimation(0,1); alpha.setDuration(1000); ivPhoto.startAnimation(alpha);
2、旋转动画
/**参数一:代码起始角度 * 参数二:代码结束角度 * 参数三和参数四为大妈旋转中心点坐标的x、y值 * */ RotateAnimation ra=new RotateAnimation(0,360,100,100); ra.setDuration(1000); ivPhoto.startAnimation(ra);
同时也可以设置参考系为自身中心点:
RotateAnimation ta=new RotateAnimation(0,360, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f); ta.setDuration(1000); ivPhoto.startAnimation(ta);
3、平移动画
TranslateAnimation ta=new TranslateAnimation(0,200,0,300); ta.setDuration(1000); ivPhoto.startAnimation(ta);
4、缩放动画
ScaleAnimation sc=new ScaleAnimation(0,2,0,2); sc.setDuration(1000); ivPhoto.startAnimation(sc);
同时也可以设置缩放的中心点:
ScaleAnimation sc=new ScaleAnimation(0,2,0,2 , Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f); sc.setDuration(1000); ivPhoto.startAnimation(sc);
5、动画合集:
通过AnimationSet,可以将动画以组合的形式展现出来:
AnimationSet set=new AnimationSet(true); set.setDuration(1000); AlphaAnimation aa=new AlphaAnimation(0,1); aa.setDuration(1000); /**将此动画加入到集合中*/ set.addAnimation(aa); TranslateAnimation ta1=new TranslateAnimation(0,100,0,200); ta1.setDuration(1000); /**将此动画加入到集合中*/ set.addAnimation(ta1); ivPhoto.startAnimation(set);
对于动画时间,android也提供了对应的监听回调,要添加相应的监听方法:
sc.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { /**动画开始*/ } @Override public void onAnimationEnd(Animation animation) { /**动画结束*/ } @Override public void onAnimationRepeat(Animation animation) { /**动画结束*/ } });
自定义View动画
除了系统提供的动画之外,我们还可以自定义动画。
1:继承Animation抽象类,重写initialize和applyTransformation方法
2:在initialize方法中进行初始化操作
3:在applyTransformation方法总进行相应的矩阵变换,一般采用Carmera简化矩阵变换。
帧动画
帧动画是顺序播放一组预先定义好的图片,类似于电影播放。系统提供了一个类AnimationDrawable来使用帧动画。
在res/drawable下新建动画view_animation_drawable.xml文件,如下:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@mipmap/ic_launcher" android:duration="500"></item> <item android:drawable="@mipmap/ic_launcher" android:duration="500"></item> <item android:drawable="@mipmap/ic_launcher" android:duration="500"></item> </animation-list>
然后将上述的Drawable作为View的背景并通过Drawable来播放动画即可:
ivPhoto.setBackgroundResource(R.drawable.view_animation_drawable); AnimationDrawable ad= (AnimationDrawable) ivPhoto.getBackground(); ad.start();
注意:帧动画比较容易引起OOM,使用时尽量避免使用尺寸较大的图片。
View动画的特殊使用场景
View动画可以在一些特殊的场景下使用:
Viewgroup中可以控制子元素的出场效果
在Activity中可以实现不同的Activity之间的切换效果。
LayoutAnimation
LayoutAnimation作用于Viewgroup,为ViewGroup指定一个动画,使它的子元素出场时具有一定的动画效果。LayoutAnimation也是一个View的动画。
使用步骤:
Step1:定义LayoutAnimation
在res/anim下新建view_layout_animation.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="0.5" android:animationOrder="normal" android:animation="@anim/anim_item" > </layoutAnimation>
属性含义:
delay:表示子元素开始动画的时间延迟。
android:animationOrder:表示子元素动画的顺序,有三种选项:noraml、reverse和random其中normal表示顺序显示;reverse表示逆向显示;random则是随机播放入场动画。
android:animation:为子元素指定具体的入场动画
Step2:为子元素指定具体的入场动画
在res/anim下新建anim_item.xml文件
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:shareInterpolator="true"> <alpha android:fromAlpha="0" android:toAlpha="1"></alpha> <translate android:fromXDelta="500" android:toXDelta="0" ></translate> </set>
Step3:为ViewGroup指定android:animation=”@anim/anim_item”属性
<ListView android:id="@+id/lv_list" android:layout_width="match_parent" android:layout_height="match_parent" android:layoutAnimation="@anim/view_layout_animation" ></ListView>
除了在XML中指定LayoutAnimation之外,还可以通过LayoutAnimationController来实现。
Animation animation= AnimationUtils.loadAnimation(this,R.anim.anim_item); LayoutAnimationController controller=new LayoutAnimationController(animation); controller.setDelay(0.5f); controller.setOrder(LayoutAnimationController.ORDER_NORMAL); lvList.setLayoutAnimation(controller);
Activity的切换效果
Activity有默认的切换效果,但是这个效果我们是可以自定义的,主要用到overridePendingTransition(int enterAnim, int exitAnim)这个方法。注意:次方法必须在startActivity(intent)或者finish()之后调用才能生效。
enterAnim:activity被打开时,所需的动画资源id;
exitAnim:activity被暂停时,所需的动画资源id;
例如:
Intent intent=new Intent(this,ActivityA.class); startActivity(intent); overridePendingTransition(R.anim.slide_right_in,R.anim.slide_right_out);
右侧进入动画:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="300" android:fromXDelta="100.0%p" android:toXDelta="0.0" /> </set>
右侧移出动画:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="300" android:fromXDelta="0.0" android:toXDelta="100.0%p" /> </set>
Android属性动画分析
对于View动画来说,动画改变的只是显示,并不能影响时间,因此在3.0之后,android退出了属性动画。
ObjectAnimator
ObjectAnimator是属性动画框架中最重要的实行类。我们可以通过ObjectAnimator的静态工厂类获取ObjectAnimator对象。
我们来实现一个简单的平移动画:
/**第一个参数为要操作的View,第二个参数为要操作的属性,而最后一个参数是一个可变数组参数*/ ObjectAnimator animator=ObjectAnimator.ofFloat(ivPhoto,"translationX",300); animator.setDuration(300); animator.start();
PropertyValuesHolder
类似视图动画中的AnimationSet,在属性动画中,如果针对于同一个对象的多个属性,需要同时作用多种动画,可以使用PropertyValuesHolder来实现。
比如平移的时候进行动X、Y轴的动画缩放,如下:
PropertyValuesHolder pv1=PropertyValuesHolder.ofFloat("translationX",300f); PropertyValuesHolder pv2=PropertyValuesHolder.ofFloat("scaleX",1f,0,1f); PropertyValuesHolder pv3=PropertyValuesHolder.ofFloat("scaleY",1f,0,1f); ObjectAnimator.ofPropertyValuesHolder(ivPhoto,pv1,pv2,pv3) .setDuration(1000).start();
ValueAnimator
ValueAnimator在属性动画中占有很重要的地位,ObjectAnimation也是继承自ValueAnimator;
ValueAnimator本身并不提供任何动画效果,它更像是一个数值发生器,用来产生具有一定规律的数字,从而让调用者来实现动画的实现过程。
使用方法:通常情况下,在ValueAnimator的AnimatorUpdateListener中监听数值的变换,从而完成动画的变换。
ValueAnimator animator1=ValueAnimator.ofFloat(0,100); animator1.setTarget(ivPhoto); animator1.setDuration(1000).start(); animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { Float value= (Float) valueAnimator.getAnimatedValue(); } });
动画事件的监听
一个完整个的动画具有Start、Repeat、End、Cancel四个过程,通过Android提供了接口,可以很方便的监听事件:
ObjectAnimator obj1=ObjectAnimator.ofFloat(ivPhoto,"alpha",0.5f); obj1.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { /**动画开始*/ } @Override public void onAnimationEnd(Animator animator) { /**动画结束*/ } @Override public void onAnimationCancel(Animator animator) { /**动画取消*/ } @Override public void onAnimationRepeat(Animator animator) { /**动画重复*/ } });
我们可以使用AnimatorListenerAdapter进行事件筛选。
obj1.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } });
AnimatorSet
动画合集,和PropertyValuesHolder类似,但是AnimationSet可以提供更精确的顺序控制。
ObjectAnimator as1=ObjectAnimator.ofFloat(ivPhoto,"translationX",300f); ObjectAnimator as2=ObjectAnimator.ofFloat(ivPhoto,"scaleX",1f,0,1f); ObjectAnimator as3=ObjectAnimator.ofFloat(ivPhoto,"scaleY",1f,0,1f); AnimatorSet set=new AnimatorSet(); set.setDuration(1000); set.playTogether(as1,as2,as3); set.start();
在XML中使用属性动画
在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>
在代码中加载属性动画:
Animator at= AnimatorInflater.loadAnimator(this,R.animator.scalex); at.setTarget(ivPhoto); at.start();
View的animate方法
3.0之后,googel给View增加了animate方法来直接驱动属性动画,代码如下:
ivPhoto.animate() .alpha(0).y(300) .setDuration(300) .withStartAction(new Runnable() { @Override public void run() { } }) .withEndAction(new Runnable() { @Override public void run() { } }).start();
理解插值器和估值器
TimeInterpolator中文翻译为事件插值器,作用是根据时间流逝的百分比来计算出当前属性值改变的百分比。
备注:
自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值算法需要实现TypeEvaluator,另外就是如果要对其他类型(非int、float、Color)做动画,那么必须奥自定义类型估值算法。
属性动画的监听器
属性动画提供了监听器用于监听动画的播放过程,主要有两个接口:
AnimatorListener和AnimatorUpdateListener;
前面已经介绍过了,这里就不说了。
对任意属性做动画
注意:在使用ObjectAnimator 的时候,需要操作的属性必须具有get和set方法,不然ObjectAnimator 就无法起作用。
如果一个属性没有get和set方法,如何来使用?
google在应用曾提供了两种方案,
1、通过自定义一个属性类,或者包装类,来简介的给这个属性增加get和set方法,
2、通过ValueAnimation来实现。
(1)使用包装类
public class WrapperView { private View mTarget; public WrapperView(View target){ mTarget=target; } public int getWidth(){ return mTarget.getLayoutParams().width; } public void setWidth(int width){ mTarget.getLayoutParams().width=width; mTarget.requestLayout(); } }
通过以上代码,就给一个属性包装了一层,并且给他提供了get、set方法。使用时,只需要操纵包专类就可以间接地调用到get、set方法了。
WrapperView view=new WrapperView(ivPhoto); ObjectAnimator.ofFloat(view,"width",500).setDuration(5000).start();
(2)采用ValueAnimation,监听动画过程,自己实现属性的改变
ValueAnimation可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们对象的属性值。
属性动画的工作原理
属性动画要求作用的对象提供属性的set方法,属性动画根据你传递的该属性的初始值和最终值,以动画的效果多次去调用set方法。每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。
如果动画的时候没有传递初始值,那么还要提供set方法,因为系统要去获取属性的初始值。
使用动画的注意事项
(1)OOM问题这个问题主要出现在帧动画中,当图片数量较多且图片较大时就容易出现OOM,尽量避免使用帧动画。
(2)内存泄漏
在属性动画中有一类无线循环的动画,这类动画需要在activity退出时及时停止,否则将导致actiivty无法释放而造成内存泄漏。
(3)兼容性问题
动画在3.0以下的系统上有兼容性问题,在某些特殊场景可能无法正常工作,因此要做好适配工作。
(4)View动画的问题
View动画是对View的影响做动画,并不是真正的改变View的状态,因此会出现东湖完成后无法隐藏的现象,即setVisibility(View.GONE)失效,这个时候要调用View.clearAnimation()清除View动画即可解决此问题。
(5)不要使用px
在进行动画的过程中,要尽量使用dp,使用平px会在不同的设备上有不同的效果。
(6)动画元素的交互
将View平移后,在android3.0以前的系统上,不管是View动画还是属性动画,新位置均无法触发单击事件,老位置仍然可以触发单击事件。
(7)硬件加速
使用动画过程中,建议开启硬件加速,会提高动画的流畅性。
相关文章推荐
- Android:MTK的Dialer模块联系人搜索
- Android Studio 如何关联源码(关联你想要的任何版本的源码)
- android 安卓APP获取手机设备信息和手机号码的代码示例
- android之屏幕适配
- Android实现滑动的七种方法
- 【Android】invalidate和postInvalidate的区别
- Android RSA加密解密
- Android数据存储五种方式总结
- Android studio中如何查看自己的打包秘钥
- [Android] 录音与播放录音实现
- Android消息机制
- Android中自定义属性attr.xml的格式详解
- AndroidStudio上项目和git项目互传
- Android性能优化之一
- android学习笔记---ScrollView布局中的显示问题
- Android如何动态的给TextView左右上下添加图片
- Android 个人理财工具一:项目概述与启动界面的实现
- Manage Android dependencies versions using gradle extra properties.
- Android 静默安装和智能安装的实现方法
- Android触摸屏事件派发机制详解与源码分析一(View篇)