VectorDrawable
矢量图形的优点在这里就不再多介绍了,并且矢量图形在安卓的Lollipop中已经实现了,相关的类就是VectorDrawable。
下面先通过一个小例子来看一下VectorDrawable的运用
layout: main.xml
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/heart"/>
drawable: heart.xml
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="250dp"
android:width="250dp"
android:viewportHeight="32"
android:viewportWidth="32" >
<path
android:name="heart"
android:fillColor="#e91e63"
android:pathData="M20.5,9.5
c-1.955,0,-3.83,1.268,-4.5,3
c-0.67,-1.732,-2.547,-3,-4.5,-3
C8.957,9.5,7,11.432,7,14
c0,3.53,3.793,6.257,9,11.5
c5.207,-5.242,9,-7.97,9,-11.5
C25,11.432,23.043,9.5,20.5,9.5z"/>
vector>
效果:
是不是感到十分神奇,一个心型图案就这样表现出来了,在这个过程中没有使用任何png图片。
其中这里最让人不解的是pathData里面的那些数字,正是这些数字让这个drawable呈现出心形。pathData指的是绘制一个图形所需要的路径信息,那么问题来了,我怎么知道该如何绘制呢?
w3c的文档中详细讲解了绘制的规则:http://www.w3.org/TR/SVG11/paths.html#PathData 。其实在svg格式的图像中也是使用这种规则,而且在安卓中android.graphics.Path Api对路径的定义也差不多是这种规则。
虽然有对path 规则的绘制教程,但是要创造出现有安卓中各种图标的效果是很难的,要让VectorDrawable有实际价值,肯定不能让开发者去想办法实现这些图形的绘制,而是原本就有很多现成的图像可用,8000个已分类好的扁平化图标(PNG/SVG/WEBFONT)http://www.shejidaren.com/8000-flat-icons.html, 从网上的搜索结果来看svg的图标是大有人在。
SVG Path Data
下面对一些常用的命令来做一下介绍:
1. M: move to 移动绘制点
2. L:line to 直线
3. Z:close 闭合
4. C:cubic bezier 三次贝塞尔曲线
5. Q:quatratic bezier 二次贝塞尔曲线
6. A:ellipse 圆弧
参数:
7. M (x y) 移动到x,y
8. L (x y) 直线连到x,y,还有简化命令H(x) 水平连接、V(y)垂直连接
9. Z,没有参数,连接起点和终点
10. C(x1 y1 x2 y2 x y),控制点x1,y1 x2,y2,终点x,y
11. Q(x1 y1 x y),控制点x1,y1,终点x,y
12. A(rx ry x-axis-rotation large-arc-flag sweep-flag x y)
rx ry 椭圆半径
x-axis-rotation x轴旋转角度
large-arc-flag 为0时表示取小弧度,1时取大弧度
sweep-flag 0取逆时针方向,1取顺时针方向
AnimatedVectorDrawable
VectorDrawable也是可以做各种各样的动画的,AnimatedVectorDrawable类可以去创建一个矢量资源的动画。
你通常在三个XML文件中定义矢量资源的动画载体:
1. 元素的矢量资源动画,在res/drawable/(文件夹)
2. 元素的矢量资源,在res/drawable/(文件夹)
3. 元素的一个或多个对象动画器,在res/anim/(文件夹)
矢量资源动画能创建和元素属性的动画。元素定义了一组路径或子组,并且元素定义了要被绘制的路径。
当你想要创建动画时去定义矢量资源,使用android:name属性分配一个唯一的名字给组和路径,这样你可以从你的动画定义中查询到它们。
下面来看两个例子,这两个例子可以从https://github.com/chiuki/animated-vector-drawable中得到。
Clock
MainActivity.java
public class MainActivity extends Activity {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock);
imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animate();
}
});
}
private void animate() {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
}
}
布局文件:就一个ImageView,使用矢量动画图像作为source。
layout: activity_clock.xml
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/nine_to_five"/>
定义一组矢量图形的动画
drawable:nine_to_five.xml
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/clock" >
<target
android:name="hours"
android:animation="@anim/hours_rotation" />
<target
android:name="minutes"
android:animation="@anim/minutes_rotation" />
animated-vector>
矢量图形
drawable:clock.xml
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="200dp"
android:width="200dp"
android:viewportHeight="100"
android:viewportWidth="100" >
<group
android:name="minutes"
android:pivotX="50"
android:pivotY="50"
android:rotation="0">
<path
android:strokeColor="@android:color/holo_green_dark"
android:strokeWidth="4"
android:strokeLineCap="round"
android:pathData="M 50,50 L 50,12"/>
group>
<group
android:name="hours"
android:pivotX="50"
android:pivotY="50"
android:rotation="0">
<path
android:strokeColor="@android:color/holo_blue_dark"
android:strokeWidth="4"
android:strokeLineCap="round"
android:pathData="M 50,50 L 24,50"/>
group>
<path
android:strokeColor="@android:color/holo_red_dark"
android:strokeWidth="4"
android:pathData="M 50,50 m -48,0 a 48,48 0 1,0 96,0 a 48,48 0 1,0 -96,0"/>
vector>
动画
anim:hours_rotation.xml
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="8000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="240"
android:interpolator="@android:anim/linear_interpolator"/>
anim:minutes_rotation.xml
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:repeatCount="7"
android:interpolator="@android:anim/linear_interpolator"/>
注意这里的android:propertyName使用rotation,当然在下个例子中我们用的是android:propertyName=”pathData”,可以对比一下。
Face:
layout: activity_face.xml
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/smiling_face"/>
drawable:smiling_face.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/face" >
<target
android:name="mouth"
android:animation="@anim/smile" />
animated-vector>
drawable:face.xml
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="200dp"
android:width="200dp"
android:viewportHeight="100"
android:viewportWidth="100" >
<path
android:fillColor="#ff0"
android:pathData="M 50,50 m -48,0 a 48,48 0 1,0 96,0 a 48,48 0 1,0 -96,0"/>
<path
android:fillColor="@android:color/black"
android:pathData="M 35,40 m -7,0 a 7,7 0 1,0 14,0 a 7,7 0 1,0 -14,0"/>
<path
android:fillColor="@android:color/black"
android:pathData="M 65,40 m -7,0 a 7,7 0 1,0 14,0 a 7,7 0 1,0 -14,0"/>
<path
android:name="mouth"
android:strokeColor="@android:color/black"
android:strokeWidth="4"
android:strokeLineCap="round"
android:pathData="M 30,75 Q 50,55 70,75"/>
vector>
anim:smile.xml
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M 30,75 Q 50,55 70,75"
android:valueTo="M 30,65 Q 50,85 70,65"
android:valueType="pathType"
android:interpolator="@android:anim/accelerate_interpolator"/>
注意这里用的是属性是android:propertyName=”pathData”
Reference
http://mobile.51cto.com/news-478709.htm
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0123/2346.html
http://blog.csdn.net/xu_fu/article/details/44004841
http://www.w3.org/TR/SVG11/paths.html#PathData
https://github.com/chiuki/animated-vector-drawable
https://gist.github.com/nickbutcher/b3962f0d14913e9746f2