Android群英传笔记——第七章:Android动画机制和使用技巧
Android群英传笔记——第七章:Android动画机制和使用技巧
想来,最 近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了
今天看了第七章,Android动画效果一直是人家中十分重要的一部分,从早期的Android版本中,由于动画机制和绘图机制的不健全,Android的人机交互备受诟病,Android从4.X开始,特别是5.X,动画越来越完善了,Google也开始重视这一方面了,我们本章学习的主要内容有
- Android视图动画‘
- Android属性动画
- Android动画实例
一.Android View动画框架
Animation动画框架定义了透明度,旋转,缩放个移动等几种动画,而且控制了整个的View,实现原理是每次绘制视图的时候View所在的ViewGroup中drawChild函数获取该View的Animation的Transformation值,然后调用了canvas.concat方法,通过矩阵运算完成动画帧,如果动画没有完成则继续调用invalidate()方法启动下回绘制来驱动动画,从而完成整个动画的绘制
视图动画使用简单,效果丰富,它提供了AlphaAnimation,RotateAnimatio,TranslateAnimation,ScaleAnimation四种动画方式,并提供了Animationset动画集合,混合使用多种动画,在Android3.0之前,视图动画一家独大,但随着Android3.0之后属性动画框架的推出它的风光就大不如前了。相比属性动画,视图动画的一个非常大的缺陷就是不具备交互性,当某个元件发生视图动画后,其响应事件的位置还依然在动画前的地方,所以视图动画只能做普通的显示效果,避免交互的发生,但是它的优点也非常明显,即效率比较高且使用方便。视图动画使用非常简单, 不仅可以通过XML文件来描述一个动画过程,同样也可以使用代码来控制整
个动画过程下面这个实例就列举了一些简单的视图动画使用方法
1.透明动画
为视图增加透明度的变换动画
AlphaAnimation al = new AlphaAnimation(0,1);al.setDuration(2000);alpha.startAnimation(al);
2.旋转动画
RotateAnimation ro = new RotateAnimation(0,300,100,100); ro.setDuration(2000); rotate.setAnimation(ro);
3.平移动画
TranslateAnimation tr = new TranslateAnimation(0,200,0,300);tr.setDuration(2000);translate.setAnimation(tr);
4.缩放动画
ScaleAnimation sc = new ScaleAnimation(0,2,0,2); sc.setDuration(2000); scale.setAnimation(sc);
5.动画集合
AnimationSet setAnimation = new AnimationSet(true);setAnimation.setDuration(2000);AlphaAnimation als = new AlphaAnimation(0,1);als.setDuration(2000);setAnimation.addAnimation(als);RotateAnimation ros = new RotateAnimation(0,300,100,100);ros.setDuration(2000);setAnimation.addAnimation(ros);set.startAnimation(setAnimation);
我们一起来运行一下看效果
当然,有动画,就有监听,我们来监听一下动画,以透明动画为例
AlphaAnimation al = new AlphaAnimation(0,1); al.setDuration(2000); alpha.startAnimation(al); al.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { Log.i("Animation","开始"); } @Override public void onAnimationEnd(Animation animation) { Log.i("Animation","结束"); Toast.makeText(MainActivity.this,"动画结束",Toast.LENGTH_LONG).show(); } @Override public void onAnimationRepeat(Animation animation) { } });
执行之后打印LOG
当然,我们眼见为实
通过监听,我们就可以了解动画的动向了
二.Android属性动画分析
属性动画在Animator框架里的,用的最多的也就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化的控制,只控制一个对象的属性,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画,而且ObjectAnimator能够自动驱动,单证各种好处,我们来看一下
1.ObjectAnimator
ObjectAnimator是属性动画框架中最重要的实行类,创建一个ObjectAnimator只需通过他
的静态工厂类直接返回一个ObjectAnimator对象,参数包括一个对象和对象的属性名字,但这
个属性必须有get和对函数,内部会通过Java反射机制来调用set函数修改对象属性值.同样
你也可以调用setIn设置相应的差值器。 下面这个小例子就完成了一个非常简单的平
移动画,
在前面的讲解中说到,以前的动画框架所产生的动画,并不能改变事件响应的位置,它只是单纯地修改了显示.如果使用旧的视图动画产生上面的效果,那么按钮的实际点击有效区依然在原来的地方,点击移动后的地方是不会有点击事件发生的.而属性动圆则不同,由于它真实地改变了一个View的属性,所以事件响应的区域也同样发生了改变,这时候点击移动后的按钮, 就会响应点击事件了
让我们来看看这个简单的平移动画是如何实现的.麻雀虽小五脏俱全,这个简单的例子基本上就涵盖了ObjectAnimator的所有知识
ObjectAnimator ob = ObjectAnimator.ofFloat(object,"translationX",300); ob.setDuration(2000); ob.start();
通过ObjectAnimator的静态工厂方法,创建个ObjectAnimator对象,第一个参数自然是要操纵的view,第二个参数则是要操纵的属性 而最后个参数是一个可变数组参数,需要传递进去该属性变化的一个取值过程,
不过,在使用ObjectAnimator的时候,有一点是非常重要的,就是操纵的set,get方法,不然ObjectAnimator是无效的,下面我们具体举一些值
translationX和 translationY:这两个属性作为一种增量来控制着View对象从它布局容器的左上角坐标便宜的位置。
rotation、rotationX和rotationY:这三个属性控制View对象围绕支点进行2D和3D旋转
scaleX和scaleY. 这两个属性控制着View对象围绕它的支点进行2D缩放。
pivotX和pivotY:这两个属性控制着view对象的支点位置,围绕这个支点进行旋转和缩放变换处理,默认情况下,该支点的位置就是View对象的中心点。
x和y这是两个简单实用的属性,它描述了View对象在它的容器中的最终位置,它是最初的左上角坐标和 translationX和 translationY值的累计和
alpha:它表示View对象的alpha透明度,默认值是1(不透明),0代表完全透明(不可见)
由以上可知,视图动画所实现的动画效果,在这里基本都已经包含了,那么如果一个属性没有get,set方法,属性动画是不是就束手无策了答案当然是否定的,google在应用层提供了两种方案来解决这个问题, 一个是通过自定义一个属性类或者包装类,来间接地给这个属性增加get方法:或者通过ValusAnimator来实现,ValusAnimator在后面的内容中会讲到, 这里先来看看如何使用包装类的方法给一个属性增加set,get方法:
private 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(); } }
通过上面的代码就给一个属性包装上了一层,并且提供lset,get方法,使用时操作就行了
WrapperView vi = new WrapperView(alpha);ObjectAnimator.ofInt(vi,"width",500).setDuration(2000).start();
2.PropertyValuesHolder
这个类类似视图动画中的AnimationSet,就是把动画给组合起来,在属性动画中,如果针对一个对象的多个属性,就同时需要多个动画了,可以使用PropertyValuesHolder,来实现,比如需要在平移的过程中,同时改变x,y的缩放,可以这样实现
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",300f);PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0,1f);PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0,1f); ObjectAnimator.ofPropertyValuesHolder(alpha,pvh1,pvh2,pvh3).setDuration(2000).start();
3.ValueAnimator
ValueAnimator这个属性在动画当中有很大的地位,虽然不想ObjectAnimator那样,耀眼,但是他确实属性动画的核心所在,ObjectAnimator也是继承自他
public final class ObjectAnimator extends ValueAnimator
ValueAnimator本身不提供任何动画,他更像是一个数值发生器,用来产生一定具有规律的数字,从而让调用者控制动画的整个过程,我们举个例子来说明
ValueAnimator va = ValueAnimator.ofFloat(0,100); va.setTarget(value); va.setDuration(2000).start(); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float values = (float) animation.getAnimatedValue(); Log.i("数值",values+""); } });
我们运行一下
4.动画事件的监听
一个完整的动画是具有,start,repeat,end,cancel四个过程的,通过Android的接口,我们很容易监听到这几个事件
ob.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) { } });
当然,大部分的场景吗,我们只关心动画结束,所以,Android也提供了一个AnimatorLisistenerAdapter来让你自己选择监听事件
va.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } });
5.AnimatorSet
对于一个属性同时作用在一个view上,前面已经有一个PropertyValuesHolder了,而AnimatorSet不仅能实现,而且能更精准的控制顺序,同样是实现PropertyValuesHolder的动画,AnimatorSet是这样实现的
ObjectAnimator animator1 = ObjectAnimator.ofFloat(alpha, "translationX", 300f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(alpha, "scaleX", 1f, 0, 1f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(alpha, "scaleY", 1f, 0, 1f); AnimatorSet set = new AnimatorSet(); set.setDuration(2000); set.playTogether(animator1,animator2,animator3); set.start();
在属性动画中,AnimatorSet正是通过playTogether等方法控制多个动画协同工作,从而控制播放顺序的
6.在XML中定义动画
属性动画同样的可以定义在xml中,我们也去玩玩
<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="2.0" android:valueType="floatType">objectAnimator>
在代码中引用
/** * 引用xml动画 * @param v */ private void scaleX(View v){ Animator anim = AnimatorInflater .loadAnimator(this,R.animator.animator); anim.setTarget(v); anim.start(); }
7.View的animate方法
在Android3.0,Google给view增加了animate方法直接来驱动属性动画,代码如下,我们可以发现,其实animate就是属性动画的一种缩写
animate.animate().alpha(0).y(300).setDuration(2000).withStartAction(new Runnable() { @Override public void run() { } }).withEndAction(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { } }); } }).start();
三.Android布局动画
所谓的布局动画,就是作用在ViewGruop中给View添加的过渡效果,最简单的方法是在xml中打开
android:animateLayoutChanges="true"
不过这都是Android自带的效果,渣渣
我们还可以通过LayoutAnimationController来定义
ll = (LinearLayout) findViewById(R.id.ll); //设置过渡动画 ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1); sa.setDuration(2000); LayoutAnimationController lc = new LayoutAnimationController(sa, 0.5f); lc.setOrder(LayoutAnimationController.ORDER_NORMAL); //设置布局动画 ll.setLayoutAnimation(lc);
通过上面。就可以给布局正加一个视图动画,让子View出现的时候有一个缩放动画,在apiDemo中这个例子还是很经典的
- LayoutAnimationController.ORDER_NORMAL 顺序
- LayoutAnimationController.ORDER_RANDOM 随机
- LayoutAnimationController.ORDER_REVEESE 反序
四.Interpolators(插值器)
插值器在动画中是一个非常重要的概念,我们通过插值器可以定义动画变换速率,这一点非常类似物理中的加速度,其作用主要是目标变化对应的变化,同样的一个动画变换起始值,在不同的插值器的作用下,每个单位时间内所达到的变换值都是不一样的,例如一个平移动画,如果使用线性插值器,那么在持续时间内单位时间所移动的距离都是一样的,如果使用加速度插值器,那么单位时间内所移动的速度越来越快,大家如果把插值器的概念理解为一个人进行万米长跑,规定一个小时到达,有的人怕时间来不及一开始就加速跑但是到后面速度越来越慢,而有的人开始节省体力,所以开始跑的比较慢,后来越跑越快直到终点,不管怎么跑,最终他们的都是在规定的时间到达终点,唯一不同的是他们的跑的速度不同,通过这个例子,我们可以很好的理解插值器的概念
五.自定义动画
创建自定义动画很简单,只需要实现applyTransformation的逻辑就可以,不过通常情况下,我们还要覆盖父类的initialize方法来完成一些初始化工作,
@Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); }
第一个参数interpolatedTime是前面说的插值器的时间因子,这个因子是由动画当前完成的百分比和当前时间对应的差值计算的,取值范围在0-1.0,第二个参数就非常简单了,她是矩阵的封装类,一般使用这个类获取当前的矩阵对象,代码如下
Matrix matrix = t.getMatrix();
通过改变获得的matrix 对象,可以将动画效果实现,而对于matrix 的变换操作,基本上可以实现任何效果,我们实现一个电视机关闭的效果
@Override protected void applyTransformation(float interpolatedTime, Transformation t) { Matrix matrix = t.getMatrix(); matrix.preScale(1, 1 - interpolatedTime, width,height); super.applyTransformation(interpolatedTime, t); }
当然我们可以设置更加精准的插值器,,从而对不同的过程采用不同的动画效果,模拟的更加逼真
接下来我们结合矩阵,并且使用Canmera来实现一个3D的效果,要注意的是,这里所指的Camera不是相机,而是这个类,他封装了openGl的3D动画,我们继续用代码来实现
@Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); setDuration(2000); setFillAfter(true); setInterpolator(new BounceInterpolator()); w = width / 2; h = height / 2; } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { Matrix matrix = t.getMatrix(); // matrix.preScale(1, 1 - interpolatedTime, w,h); mCamera.save(); //设置旋转角度 mCamera.rotate(0, 180, 360); mCamera.restore(); //通过pre方法设置矩形作用前的偏移量来改变旋转中心 matrix.preTranslate(w, h); matrix.postTranslate(-w, -h); super.applyTransformation(interpolatedTime, t); }
通过以上的方法,就可以实现了
六.Android 5.X SVG矢量动画机制
黑科技来了,Google在Android5.X中增加了对SVG矢量图形的支持,这对于创造新的高效率动画具有很深远的意义,首先,我们来了解一下什么是SVG
- 可伸缩矢量图形
- 定义用于网络的基于矢量的图形
- 使用xml格式定义图形
- 图片在放大或者改变尺寸的情况下其图形质量不会有所损失
- 万维网联盟的标准
- 与诸多DOM和XSL之类的W3C标准是一个整体
SVG在web上应用非常广泛,在Android5.X之前的Android版本上,大家可以通过一些第三方库在Android中使用SVG,而在Android5.X后,Android中添加了对< path >标签的支持,从而让开发者可以使用SVG来创建更加丰富的动画效果,那么SVG对传统的Bitmap,究竟有什么好处呢?bitmap通过每个像素点上存储色彩信息来表达图像,而SVG是一个绘图标准,与之相对,最大的优势是SVG放大不会失真,而且bitmap需要不同分辨率适配,SVG不需要
1.< path >标签
使用< path >标签来创建SVG,就是用指令的方式来控制一支画笔,列入,移动画笔来到某一个坐标位置,画一条线,画一条曲线,结束,< path >标签所支持的指令大致有一下几种
M = moveto(M X,Y):将画笔移动到指定的坐标位置,但未发生绘制
L = lineto(L X,Y):画直线到指定的位置
H = horizontal lineto( H X):画水平线到指定的X坐标位置
V = vertical lineto(V Y ):画垂直线到指定的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 curvrto(T,ENDX,ENDY):映射前面路径的重点
A = elliptical Are(A RX,RY,XROTATION,FLAG1FLAG2,X,Y):弧线
Z = closepath() 关闭路径
使用上面的指令时,需要注意的几点
- 坐标轴以(0,0)位中心,X轴水平向右,Y轴水平向下
- 所有指令大小写均可,大写绝对定位,参照全局坐标系,小写相对定位,参照父容器坐标系
- 指令和数据间的空格可以无视
- 同一指令出现多次可以用一个
2.SVG常见指令
L
绘制直线的指令是“L”,代表从当前点绘制直线到给定点,“L”之后的参数是一个点坐标,如“L 200 400”绘制直线,同时,还可以使用“H”和“V”指令来绘制水平竖直线,后面的参数是x坐标个y坐标
M
M指令类似Android绘图中的path类moveto方法,即代表画笔移动到某一点,但并不发生绘图动作
A
A指令是用来绘制一条弧线,且允许弧线不闭合,可以把A指令绘制的弧度想象成椭圆的某一段A指令一下有七个指令
- RX,RY指所有的椭圆的半轴大小
- XROTATION 指椭圆的X轴和水平方向顺时针方向的夹角,可以想象成一个水平的椭圆饶中心点顺时针旋转XROTATION 的角度
- FLAG1 只有两个值,1表示大角度弧度,0为小角度弧度
- FLAG2 只有两个值,确定从起点到终点的方向1顺时针,0逆时针
- X,Y为终点坐标
SVG的指令参数非常的复杂,但是再Android中,不需要绘制太多的SVG图像,后面会有几个小案例
3.SVG编辑器
SVG参数的写法固定而且复杂,因此完全可以使用程序来实现,所以一般通过SVG编辑器来编辑SVG图像,网上有很多在线的编辑器,通过可视化编辑图像之后,点击view source可以转换成SVG代码
地址:http://editor.method.ac/
下载离线的SVG编辑器,由很多强大的功能,这里就不一一赘述了
4.Android中使用SVG
Google在Android5.X后给我们提供了两个新的API来支持SVG
VectorDrawable
AnimatedVectorDrawable
其中,VectorDrawable可以让你创建基于XML的SVG图像,并且结合AnimatedVectorDrawable来实现动画效果
-1 VectorDrawable
在XML中创建一个静态的SVG,通过这个结构
<?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="100dp" android:viewportWidth="100dp">vector>
这个代码之中包含了两组高宽,width,和height是表示SVG图像的具体大小,后面的是表示SVG图像划分的比例,后面再绘制path时所使用的参数,就是根据这两个值来进行转换的,比如上面的代码,将200dp划分100份,如果在绘图中使用坐标(50,50),则意味着该坐标为正中间,现在我们加上path标签
<?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="100dp" android:viewportWidth="100dp"> <group android:name="svg1" android:rotation="0"> <path android:fillColor="@android:color/holo_blue_light" android:pathData="M 25 50 a 25,25 0 1,0 50,0" /> group>vector>
通过添加< path>标签绘制一个SVG齐总pathData就是图形所用到的指令了,先用M指令,将画笔移动到(25 , 50)的位置,再通过A指令来绘制一个圆弧并且填充他,通过以上代码,就可以绘制一个SVG图形了
填充指令
-2 AnimatedVectorDrawable
AnimatedVectorDrawable的作用是给VectorDrawable提供动画效果,Google的工程师将AnimatedVectorDrawable比喻一个胶水,通过AnimatedVectorDrawable来连接静态的VectorDrawable和动态的objectAnimator
下面我们来看看具体是怎么样来做的,首先我们在xml中定义一个< animated-vector>,来申明对AnimatedVectorDrawable的使用,并且指明是作用在path或者group上
<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/verctors"> <target android:animation="@android:anim/fade_in" android:name="test"> target>animated-vector>
对应的vector即为静态的VectorDrawable
<?xml version="1.0" encoding="utf-8"?><vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="200dp" android:width="200dp" android:viewportWidth="100" android:viewportHeight="100"> <group android:name="test" android:rotation="0" > <path android:strokeColor="@android:color/holo_blue_light" android:strokeWidth="2" android:pathData="M 25 50 a 25 , 25 0 1 , 0 50 ,0" > path> group>vector>
需要注意的是,AnimatedVectorDrawable中指明的target和name属性,必须与VectorDrawable中需要的name保持一致,这样系统能找到找到要实现的动画元素,最后,通过AnimatedVectorDrawable中的target和animation属性,将一个动画作用在对应的name上,objectanimator代码如下
<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360">objectAnimator>
最后,我们看到的,对动画效果的实现,还是通过属性动画来完成的,只是属性稍有不同
在< group>标签和< path>标签中添加rotation,fillColor,pathData属性,那么在objecyAnimator中,就可以通过指定,android:valueFrom=XXX,和android:property=”XXX”属性,控制动画的起始值,唯一需要注意的是,如果指定属性为pathData,那么需要添加一个属性android:valueType-“pathType”来告诉系统进行pathData变换,类似的情况,可以使用rotation来进行旋转变换,使用fileColor实现变换颜色,使用pathData进行形状,位置的变换
当所有的XML准备好之后,我们就可以直接给一个imageview设置背景了
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/myver"/>LinearLayout>
在程序中,我们只要使用这个start方法开启动画就可以‘
在初步了解SVG动画之后,我们来写几个实际的小例子来见识一下SVG的强大
5.SVG动画实例
-1 线图动画
在android5.X之后,Google大量引入了线图动画,当页面发生改变的时候,页面的icon不再是生硬的切换,而是通过非常生动的动画,转换成另一种形态
要实现这样的一个效果,我们首先要创建一个SVG图形,即动态的VectorDrawable
我们要实现的效果就是上下两根线,然后他们形成一个X的效果path1和path2分别绘制了两条直线
<?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:pathData="M 20,80 L 50,80 80 , 80" android:strokeColor="@android:color/holo_green_dark" android:strokeLineCap="round" android:strokeWidth="5" /> <path android:name="path2" android:pathData="M 20,20 L 50,20 80 , 20" android:strokeColor="@android:color/holo_green_dark" android:strokeLineCap="round" android:strokeWidth="5" /> group>vector>
path1和path2分别绘制了一条直线,
每条线都有三个点控制,接下来就是变换的动画了
<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="5000" android:propertyName="pathData" 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/bounce_interpolator">objectAnimator>
在以上代码中,定义了一个pathType动画,并且指定了起点,中点,终点
android:valueFrom="M 20, 80 L 50 , 80 80 ,80"android:valueTo="M 20 ,80 L 50 ,50 80 ,80"
这两个值是对应的起始点,不过需要注意的是,SVG的路径变换属性动画中,变换前后阶段属必须相同,这也是前面需要使用的三个点看来绘制一条直线的原因,,有了VectorDrawable和objectAnimator,现在只需要AnimatedVectorDrawable将他们加起来就起来
<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ver2"> <target android:name="path1" android:animation="@anim/anim2" /> <target android:name="path2" android:animation="@anim/anim2" />animated-vector>
针对trick这样的一个VectorDrawable中的path1和path2的路径,分别使用了objectAnimator,最后只需要去启动动画就可以了
package com.lgl.animations;import android.graphics.drawable.Animatable;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.ImageView;/** * 绘制SVG * Created by LGL on 2016/4/16. */public class SVGActivity extends AppCompatActivity { private ImageView iv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_svg); iv = (ImageView) findViewById(R.id.iv); iv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } private void anim() { Drawable drawable = iv.getDrawable(); if (drawable instanceof Animatable) { ((Animatable) drawable).start(); } }}
-2 模拟三球仪
三球仪是天体文学中的星象仪器,用来模拟地球,月亮和太阳的运行轨迹,如图
我们也来实现以下
<?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 android:name="sun" android:pivotX="60" android:pivotY="50" android:rotation="0"> <path android:name="path_sun" android:fillColor="@android:color/holo_blue_light" android:pathData="M 50 ,50 a 10,10 0 1 , 0 20 , 0 a 10 ,10 0 1 , 0 -20 ,0" /> <group android:name="earth" android:pivotX="75" android:pivotY="50" android:rotation="0"> <path android:name="path_earth" android:fillColor="@android:color/holo_orange_dark" android:pathData="M 70 , 50 a 5 , 5 0 1 , 0 10 ,0 a 5 , 5 0 1,0 -10 ,0" /> <group> <path android:fillColor="@android:color/holo_green_dark" android:pathData="M 90,50 m -5 0 a 4 , 4 0 1,0 8 0 a 4 , 4 0 1 , 0 - 8 , 0" /> group> group> group>vector>
可以从代码冲发现,sun在这个group中,有一个earth的group,我们这里再定义一个动画
<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" >objectAnimator>
后面的跟前面提到的差不多,就不写了
-3.轨迹动画
android对SVG的支持带来了很多的特效,我们来做一个搜索的放大镜效果吧,先定义好轨迹
<?xml version="1.0" encoding="utf-8"?><vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="160dp" android:height="30dp" android:viewportHeight="30" android:viewportWidth="160"> <path android:name="search" android:pathData="M141 , 17 A9 ,9 0 1 , 1 ,142 , 16 L149 ,23" android:strokeAlpha="0.8" android:strokeColor="#ff3570be" android:strokeLineCap="square" android:strokeWidth="2" /> <path android:name="bar" android:pathData="M0,23 L149 ,23" android:strokeAlpha="0.8" android:strokeColor="#ff3570be" android:strokeLineCap="square" android:strokeWidth="2" />vector>
后面动画的部分就不详细写了,受开发环境的限制,有兴趣的可以拿着原书研究下
七.android动画特效
通过前面的学习,我们基本掌握了android中的各种动画了,所以,在这里做几个小例子
1.卫星菜单
当点击小红点的时候,弹出菜单,并且带有一个缓冲的效果,这就是Google在MD中强调的动画过渡,要怎么实现这个动画呢,其实还不是就一个开始一个结束动画,看代码
/** * 执行动画 */ private void statAnim(){ ObjectAnimator animator0 = ObjectAnimator.ofFloat(iv0,"alpha",1F,0.5F); ObjectAnimator animator1 = ObjectAnimator.ofFloat(iv1,"translationY",200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(iv2,"translationX",200F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(iv3,"translationY",-200F); ObjectAnimator animator4 = ObjectAnimator.ofFloat(iv4,"translationX",-200F); AnimatorSet set = new AnimatorSet(); set.setInterpolator(new BounceInterpolator()); set.playTogether(animator0,animator1,animator2,animator3,animator4); set.start(); mFlag = false; }
下面就是点击事件
iv0.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mFlag){ statAnim(); }else{ closeAnim(); } } });
2.计时器动画
通过这个示例,我们了解一下ValueAnimator的效果,当用户点击后,数字不断增加,好的,我们开始
package com.lgl.animations;import android.animation.ValueAnimator;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.TextView;/** * 绘制SVG * Created by LGL on 2016/4/16. */public class SVGActivity extends AppCompatActivity { private TextView tv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_svg); tv = (TextView) findViewById(R.id.tv); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tvTimer(tv); } }); } private void tvTimer(final View view){ ValueAnimator va = ValueAnimator.ofInt(0,100); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { ( (TextView)view).setText("$"+(Integer)animation.getAnimatedValue()); } }); va.setDuration(3000); va.start(); }}
我们来运行一下
3.下拉展开动画
下面我们来实现一个展开的动画,首先,XML是这样的
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_blue_bright" android:gravity="center_vertical" android:onClick="llClick" android:orientation="horizontal"> <ImageView android:id="@+id/app_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:gravity="left" android:text="Click me" android:textSize="30sp" /> LinearLayout> <LinearLayout android:id="@+id/hidden_view" android:layout_width="match_parent" android:layout_height="40dp" android:background="@android:color/holo_orange_light" android:orientation="horizontal" android:visibility="gone"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/tv_hidden" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:text="I Am Hidden" android:textSize="20sp" /> LinearLayout>LinearLayout>
为了区分两个不同的线性布局,我们给他设置了不同的颜色背景,好的,我们开始实现
package com.lgl.animations;import android.animation.ValueAnimator;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;/** * 下拉展开动画 * Created by LGL on 2016/4/18. */public class AnimaActivity extends AppCompatActivity { private LinearLayout mHiddenView; private float mDensity; private int mHiddenViewMeasuredHeight; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_anima); mHiddenView = (LinearLayout) findViewById(R.id.hidden_view); //获取像素密度 mDensity = getResources().getDisplayMetrics().density; //获取布局的高度 mHiddenViewMeasuredHeight = (int) (mDensity*40+0.5); } public void llClick(View view){ if (mHiddenView.getVisibility() == View.GONE){ animOpen(mHiddenView); }else{ animClose(mHiddenView); } } private void animOpen(final View view){ view.setVisibility(View.VISIBLE); ValueAnimator va = createDropAnim(view,0,mHiddenViewMeasuredHeight); va.start(); } private void animClose(final View view){ int origHeight = view.getHeight(); ValueAnimator va = createDropAnim(view,origHeight,0); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { view.setVisibility(View.GONE); } }); va.start(); } private ValueAnimator createDropAnim(final View view,int start,int end) { ValueAnimator va = ValueAnimator.ofInt(start, end); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int) animation.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.height = value; view.setLayoutParams(layoutParams); } }); return va; }}
好的,我们开始运行一下
OK,本章就到这里
笔记下载:http://pan.baidu.com/s/1c0U7k2W 密码:9v0g
Demo下载:http://download.csdn.net/detail/qq_26787115/9495167
更多相关文章
- Android属性动画——实现灵动菜单效果
- Android 属性动画ValueAnimator和ObjectAnimator的高级用法
- android:layout_weight属性的工作原理
- 原来Android还可以这样通过反射,获取jar包属性及方法
- Android Layout布局文件里的android:layout_height等属性为什么.
- [Mugeda HTML5技术教程之18]如何在Android应用中使用Mugeda动画
- android的ImageView中XML属性src和background的区别
- Android布局之LinearLayout weight属性的理解
- Android动画基础-Tween和Frame动画