《Android群英传》读书笔记(8)第七章:Android动画机制与使用技巧
2015-12-20 13:17
561 查看
1.视图动画
Android视图动画的分类:透明度动画——AlphaAnimation
旋转动画——RotateAnimation
位移动画——TranslateAnimation
缩放动画——ScaleAnimation
动画集合——AnimationSet
视图动画的监听方式:
animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } });2.属性动画
视图动画Animation存在一定的局限性,动画改变的只是显示,并不能响应事件,因此属性动画Animator就应运而生。Animator中使用最多的就是AnimatorSet和ObjectAnimator,AnimatorSet用来组合ObjectAnimator,ObjectAnimator只控制一个对象的属性值,而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay);设置动画之间的间隙时间,调整帧率。最重要的是属性动画通过调用属性的set、get方法来真实地控制一个View的属性值,因此强大的属性动画基本可以实现所有的动画效果。
ObjectAnimator的使用方法:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0, 300); animator.setDuration(3000); animator.start();
需要注意的是,要操纵的对象的属性必须具有get和set方法,不然属性动画就无法起效。
属性动画常用的属性:
translationX和translationY
rotation、rotationX和rotationY
scaleX和scaleY
pivotX和pivotY
x和y
alpha
如果一个属性没有get和set方法,可以通过对操作对象进行包装来实现set、get方法:
public static 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(); } }
然后对包装后的对象应用动画:
ObjectAnimator.ofInt(wrapperView, "width", wrapperView.getWidth(), wrapperView.getWidth() * 2).setDuration(3000).start();PropertyValuesHolder
类似视图动画中的AnimationSet,PropertyValuesHolder可以针对同一个对象的多个属性同时应用多种动画下面是使用示例:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",300f); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("scaleX",1f,0f); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("scaleY",1f,0f); ObjectAnimator.ofPropertyValuesHolder(view,p1,p2,p3).setDuration(3000).start();
ValueAnimator
ValueAnimator是属性动画的核心所在,它本身不提供任何效果,更像是一个数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程。ValueAnimator的使用方法如下,通常在AnimatorUpdateListener中监听数值的变换,从而完成动画的变换:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100); valueAnimator.setDuration(1000); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); //TODO use the value } });属性动画的监听
通过AnimatorListener监听动画执行的全过程:
animator.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) { } });或者使用AnimatorListener的实现类AnimatorListenerAdapter:
animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } });AnimatorSet
AnimatorSet除了能实现PropertyValuesHolder的功能之外,还能实现更为精确的控制动画播放的顺序,AnimatorSet中有playTogether()、playSequentially()、animSet.play().with()、before()、after()等方法。
在XML中使用属性动画
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="translationX" android:interpolator="@android:interpolator/accelerate_cubic" android:valueFrom="0dp" android:valueTo="100dp" android:valueType="intType" > </objectAnimator>然后在代码中进行加载:
ObjectAnimator animator = (ObjectAnimator) AnimatorInflater.loadAnimator(this,R.animator.anim);
除了使用Animator.start()方法启动动画外,在Android3.0之后Google还为View增加了animate方法来启动属性动画,代码如下所示:
view.animate() .setDuration(1000) .alpha(0) .y(300) .withStartAction(new Runnable() { @Override public void run() { } }).withEndAction(new Runnable() { @Override public void run() { } }).start();3.Android布局动画
布局动画是指作用在ViewGroup上,给ViewGroup添加View时的一个动画过渡效果,在ViewGroup的布局XML中通过android:animateLayoutChanges="true"来打开布局动画,然后有新view加入时就会显示默认的布局动画效果了。
另外还可以通过LayoutAnimationController类来自定义一个子view的过渡效果:
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1); sa.setDuration(500); LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f); lac.setOrder(LayoutAnimationController.ORDER_NORMAL); ll.setLayoutAnimation(lac);LayoutAnimationController构造方法的第一个参数是需要作用的动画,第二个参数是每个子view显示的间隔时间。当间隔不为0时可以为子view设置显示顺序:
LayoutAnimationController.ORDER_NORMAL
LayoutAnimationController.ORDER_RANDOM
LayoutAnimationController.ORDER_REVERSE
4.自定义动画
创建自定义动画需要继承自Animation类,然后重写applyTransformation方法就可以了,有时还要重写initialize()方法来完成一些初始化的工作。applyTransformation方法有以下几个参数:
applyTransformation(float interpolatedTime,Transformation t);interpolatedTime这个值就是插值器(Interpolator)的时间因子,这个值有当前动画完成的百分比和当前时间对应的插值计算得来,范围是0到1.0,第二个参数Transformation是矩阵的封装类,一般用它来获取当前的矩阵对象:
final Matrix matrix = t.getMatrix();通过改变matrix来实现动画效果,下面代码实现了模拟电视机关闭屏幕的动画效果:
public class CustomAnimation extends Animation { private int mCenterWidth; private int mCenterHeight; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); mCenterWidth = width / 2; mCenterHeight = height / 2; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); final Matrix matrix = t.getMatrix(); matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight); } }结合android.graphics.Camera类还可以实现3D的切换效果,下面是一个3D的旋转动画的代码:
public class CustomAnimation extends Animation { private int mCenterWidth; private int mCenterHeight; private Camera mCamera; @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); mCenterWidth = width / 2; mCenterHeight = height / 2; mCamera = new Camera(); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); final Matrix matrix = t.getMatrix(); mCamera.save(); mCamera.rotateY(interpolatedTime * 360); mCamera.getMatrix(matrix); mCamera.restore(); matrix.preTranslate(-mCenterWidth, -mCenterHeight); matrix.postTranslate(mCenterWidth, mCenterHeight); } }
5.SVG矢量动画
在Android5.0开始,增加了矢量图形的支持,来看一下什么是SVG
可伸缩矢量图形(Scalable Vector Graphics)
使用XML格式定义图形
图像在放大或改变尺寸的情况下其图形质量不会损失
万维网联盟标准
与诸如DOM和XSL之类的W3C标准是一个整体。
path标签指令:
M = moveto(M X,Y)——将画笔移动到指定的坐标位置
H = horizontal lineto(L X,Y)——画直线到指定的坐标位置
V = vertical lineto(V,Y)——画垂直线到指定的坐标位置
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY)——三次贝塞尔曲线
S = smooth curveto(S X2,Y2,ENDX,ENDY)——三次贝塞尔曲线
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY)——二次贝塞尔曲线
T = smooth quadratic Belzier curve(T ENDX,ENDY)——映射前面路径后的终点
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y)——弧线
Z = closepath()——关闭路径
在使用以上命令时要注意:
坐标以(0,0)为中心,X轴水平向右,Y轴竖直向下。
所有指令大小写均可,大写绝对定位,参照全局坐标系,小写相对定位,参照父容器坐标系。
指令和数据间的空格可以省略。
同一指令出现多次可以只用一个。
下面来看SVG常用命令的使用方法:
L
绘制直线的指令是L,L之后的参数是一个坐标如“L 200,400”还可以使用H和V来绘制水平和竖直线
M
M类似绘图中的path类的moveTo方法,即代表将画笔移动到某一点,并不发生绘制动作
A
A指令用来绘制一段弧线,且允许弧线不闭合。可以把A命令绘制的弧线想象成是椭圆的某一段,A指令有以下几个参数:
RX,RY指所在椭圆的半轴大小
XROTATION指椭圆的X轴与水平方向顺时针夹角,可以想象成一个水平的椭圆绕中心点顺时针旋转XROTATION的角度。
FLAG1只有两个值,1表示大角度弧线,0表示小角度弧线
FLAG2只有两个值,确定从起点到终点的方向,1为顺时针,0为逆时针。
X,Y为终点坐标
Android中使用SVG
Android中提供了VectorDrawable和AnimatedVectorDrawable来支持SVG。
VectorDrawable用于创建基于XML的SVG图形,并结合AnimatedVectorDrawable来实现动画效果。
下面是VectorDrawable的使用示例:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="100dp" android:height="100dp" android:viewportHeight="100" android:viewportWidth="100" > <group android:name="test" android:rotation="0" android:pivotX="50" android:pivotY="50" > <path android:strokeColor="@android:color/holo_orange_dark" android:strokeWidth="2" android:pathData=" M 25,50 a 25,25 0 1,0 50,0" > </path> </group> </vector>
其中的fillColor属性用来绘制填充的图形,绘制非填充的图形使用strokeColor结合strokeWidth来实现。
AnimatedVectorDrawable的作用是给VectorDrawable提供动画效果,它将VectorDrawable和属性动画进行结合,就可以实现具有动画效果的Vector了。
下面是AnimatedVectorDrawable使用示例:
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_drawable" > <target android:animation="@animator/anim" android:name="test"/> </animated-vector>其中的animation属性指向的是属性动画Animator。来看一下这个动画:
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:interpolator="@android:interpolator/accelerate_cubic" android:valueFrom="0" android:valueTo="360" > </objectAnimator>
AnimatedVectorDrawable创建好后,可以通过给ImageView等空间设置src属性进行设置然后在代码中通过((Animatable)imageView.getDrawable()).start();来开启动画。
线图动画
通过将属性动画的propertyName属性设置为pathData,就可以根据VectorDrawable的pathData属性来进行动画了。下面是使用示例,展示里两条平行线变换成叉的动画,
这是VectorDrawable文件:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="200dp" android:height="200dp" android:viewportHeight="100" android:viewportWidth="100" > <group> <path android:name="path1" android:strokeWidth="2" android:strokeColor="@android:color/holo_orange_dark" android:strokeLineCap="round" android:pathData=" M 20,80 L 50,80 80,80" /> <path android:name="path2" android:strokeWidth="2" android:strokeColor="@android:color/holo_orange_dark" android:strokeLineCap="round" android:pathData=" M 20,20 L 50,20 80,20" /> </group> </vector>属性动画文件,只列出了其中的一个,两个动画类似:
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:propertyName="pathData" android:duration="500" android:valueFrom=" M 20,80 L 50,80 80,80" android:valueTo=" M 20,80 L 50,50 80,80" android:valueType="pathType" android:interpolator="@android:anim/accelerate_interpolator" > </objectAnimator>AnimatedDrawable文件:
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_cross" > <target android:animation="@animator/anim_path1" android:name="path1"/> <target android:animation="@animator/anim_path2" android:name="path2"/> </animated-vector>
需要注意的是当属性动画的propertyName指定为pathData时,valueType属性也要指定为pathType的类型。
下面是一个搜索框的动画效果:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="60dp" android:width="320dp" android:viewportHeight="30" android:viewportWidth="160" > <group> <path android:name="search" android:strokeWidth="1.5" android:strokeAlpha="0.0" android:strokeColor="#ff3570be" android:strokeLineCap="round" android:pathData=" M141,17 A9,9 0 1,1 142,16 L149,23" /> <path android:name="bar" android:strokeWidth="1.5" android:strokeAlpha="0.8" android:strokeColor="#ff3570be" android:strokeLineCap="square" android:pathData=" M0,23 L149,23" /> </group> </vector>
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:propertyName="trimPathEnd" android:valueFrom="0" android:valueTo="1" android:duration="1000" android:interpolator="@android:interpolator/accelerate_decelerate" android:valueType="floatType" > </objectAnimator>
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_search"> <target android:animation="@animator/anim_search" android:name="search"/> <target android:animation="@animator/anim_alpha" android:name="search"/> </animated-vector>
相关文章推荐
- android中sharedPreferences的用法
- Android传感器学习之加速度传感器数据获取
- Android中ListView的优化
- Android设备获取扫码枪扫描内容
- Android-自定义控件样式之shape
- 如何在ListView中点击item控制item中的控件变化(ListView篇)
- Android客户端与服务器端简单交互
- android 图片浏览器 demo
- android-textview设置字体的行距和字间距
- android----Java DES加密算法工具类
- Android开发环境搭建
- 关于Android sdkmanager目录结构的总结
- 只需三步--轻松反编译Android Apk文件
- 两种方式去掉Android状态栏和标题栏
- Android获取服务器Json数据与Json的解析
- Android 简单的记事本
- 创建Android项目及常见错误解决
- android 自己定义开关(SwitchButton)
- 关于Android SDK Manager无法更新的解决办法
- 关于无法下载android开发工具的解决方法