Android vector 标签 pathData

本文详细介绍了SVG路径数据的基本指令及应用,包括移动、直线、弧线、贝塞尔曲线等,并通过实例展示了如何利用这些指令绘制复杂的图形。

原文:http://www.jianshu.com/p/a3cb1e23c2c4

基本规则

pathData 的指令基本都是由字母跟若干数字组成,数字之间可以用空格或者逗号隔开 (其实逗号会被忽略掉,加上逗号只是一些习惯的问题)。一般来说指令字母分为大小写两种,大写的字母是基于原点的坐标系(偏移量),即绝对位置;小写字母是基于当前点坐标系(偏移量),即相对位置。

移动

  • M x,y (m dx, dy) 移动虚拟画笔到对应的点,但是并不绘制。一开始的时候默认是在(0,0)。

直线

  • L x,y (l dx, dy) 从当前点划一条直线到对应的点。
  • H x (h dx) 从当前点绘制水平线,相当于l x,0
  • V y (v dy) 从当前点绘制垂直线,相当于l 0,y
<vector xmlns:android="http://schemas.android.com/apk/res/android"
      android:width="24dp"
      android:height="24dp"
      android:viewportWidth="24"
      android:viewportHeight="24">
  <path
      android:fillColor="#0000"
      android:strokeColor="#000"
      android:strokeWidth="0.2"
      android:pathData=" M10,10 L10,15 L15,15 L10,10"/>
</vector>

三角形
将上述代码android:pathData=" M10,10 L10,15 L15,15 L10,10"替换成以下代码效果相同

android:pathData="M10,10 l 0,5 l 5,0 l-5,-5"  
 android:pathData="M10,10 V 15 H 15 L10,10"  
 android:pathData="M10,10 v 5 h 5 l-5,-5"

闭合

  • Z(或z) 从结束点绘制一条直线到开始点,闭合路径
    上面的图形型也可以由以下代码绘制
android:pathData="M10,10 v 5 h 5 z"

弧线

  • A rx,ry x-axis-rotation large-arc-flag,sweepflag x,y
  • a rx,ry x-axis-rotation large-arc-flag,sweepflag dx,d

    rx ry 椭圆半径
    x-axis-rotation x轴旋转角度
    large-arc-flag 为0时表示取小弧度,1时取大弧度(要长的还是短的)
    sweep-flag 0取逆时针方向,1取顺时针方向
    x,y (dx,dy) 终点的位置

这个弧线的指令比起直线就相对复杂得多了,7个参数容易搞混了。来看个例子android:pathData="M8,10 a4,6 0 1,1 6 6"
弧线(大弧,顺时针)
红色(8,10) 是起点, X轴旋转的角度为0,取大弧,顺时针,蓝色(14,16) 是终点。

  • 只将x-axis-rotation 改为30跟-30分别对应下面左边跟右边的效果,可见正数是按顺时针旋转负数按逆时针旋转。
    x-axis-rotation为30(左)、-30(右)
  • 只将large-arc-flag 改为 0android:pathData="M8,10 a4,6 0 0,1 6 6"对应下图效果
    arge-arc-flag为 0
  • 只将sweep-flag改为 0 android:pathData="M8,10 a4,6 0 1,0 6 6"对应下图效果
  • weep-flag为0

二阶贝塞尔曲线

  • Q x1,y1 x,y ( q dx1,dy1 dx,dy)
  • T x,y ( t dx, dy)

    先来看看二阶贝赛尔曲线的公式

这里写图片描述

下面是对应的动画
这里写图片描述

一下子感觉清晰了不少,对于Q指令来说(x1,y1)就是P1这个控制点,(x,y)就是终点P2。P0当然就是执行指令前最后的位置。这里有一点需要说明的, q dx1,dy1 dx,dy 这个指令,两个控制点都是相对P0点的。

而T指令又是什么鬼?为什么只有两个参数?其实T指令是在你画完一条贝塞尔曲线后,只需用T指令指定终点,就能画出一条平滑的贝塞尔曲线。控制点被默认为上一次的控制点关于上次终点的中心对称点。比如上次的控制点P1是(6,6),终点P2是(8,10), 那么使用T指令后默认控制点P1`为(10,14)。

举个例子:

 android:pathData="M4,10 Q6,6 8,10 Q10,14 12,10"  
 android:pathData="M4,10 Q6,6 8,10 T12,10" 
 android:pathData="M4,10 q2,-4 4,0 q2,4 4,0"  
 android:pathData="M4,10  q2,-4 4,0 t4,0"

这四个对应的都是下面的曲线

这里写图片描述

三阶贝塞尔曲线

  • C x1,y1 x2,y2 x,y ( c dx1,dy1 dx2,dy2 dx,dy)
  • S x1,y1 x,y ( s dx1,dy1 dx, dy)

    同样,先列下公式

这里写图片描述

动画如下:

这里写图片描述

跟二阶类似,但是三阶有两个控制点,分别是P1(x1,y1),P2(x2,y2)还有终点P3(x,y)。类似的, c dx1,dy1 dx2,dy2 dx,dy 所有的点都是相对于P0,即上一次的终点。

S指令跟T指令类似。S指令相对于C指令少了一个控制点,这个控制点就是上一次最后一个控制点相对上次的终点的中心对称点。还是同样举个例子:

android:pathData="M4,10 C6,6 8,14 10,10 C12,6 14,14 16,10"
 android:pathData="M4,10 C6,6 8,14 10,10 S14,14 16,10"
 android:pathData="M4,10 c2,-4 4,4 6,0 c2,-4 4,4 6,0"
 android:pathData="M4,10 c2,-4 4,4 6,0 s4,4 6,0"

以上四个均会出现下图的效果

这里写图片描述

实践

终于把所有的指令搞清楚啦,那么接下来就来画一个比较简单的图案吧(为了一次性涉及几乎所有的指令,大家就别在意图画的很丑啦)

这里写图片描述

首先分析一下这个图的构成。它是一个圆角正方形同时里面有一个镂空的心型。先来看看正方形

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="40"
        android:viewportHeight="40">

    <path
        android:fillColor="#f24e4e"
        android:pathData="M8,4
            h24 q4,0 4,4 v24 q0,4 -4,4
            h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4"/>
</vector>

这里写图片描述

细心的同学应该注意到这里没有设置strokeColor,strokeWidth,并且fillColor也不再设置透明了,所以出现的是没有边框的填充效果。上面viewportWidth为40,则把这张图分成40个单位。

在pathData中,首先移动到A(8,4),然后水平移动了24个单位到B(32,4)。接着就是一条二阶贝塞尔曲线,起点是B,控制点是C(36,4),终点是D(36,8)。然后再画一条垂直线到(36,32)…下面的操作都是差不多,就不多说的。这里注意一点,画这个正方形是从A-B-C-D,也就是顺时针的方向,这点对接下来画心型很重要。

画完了圆角正方形,接下来就要画一个镂空的心型。有同学说再加上一个path标签,设置不同颜色就可以。这方法乍一看挺不错,但是他实现的并不是镂空的效果,而是叠加的效果。镂空的话中间的心型是透明的,但是叠加就没办法让中间的心呈透明。

那怎么实现镂空的效果呢?其实关键就是前面说的方向。前面的正方形是顺时针的方向,如果我们在pathData 后面加上另一逆时针方向的路径,就会出现取反的效果,比如

<path
        android:fillColor="#f24e4e"
        android:pathData="M8,4
            h24 q4,0 4,4 v24 q0,4 -4,4
            h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
            M2,20 h20 v-10 z"/>

在刚才的基础上加上M2,20 h20 v-10 z,这是一个逆时针方向的三角形,会变成下面这样
这里写图片描述

也就是说,我们只需要画一个逆时针方向的心型,就会出现上面的那个效果。先看看代码

<path
        android:fillColor="#f24e4e"
        android:pathData="M8,4
            h24 q4,0 4,4 v24 q0,4 -4,4
            h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
            M20,15
            a5,6 -15 0 0 -9,2
            c0,5 4,6 9,12
            c5,-6 9,-7 9,-12
            a5,6 15 0 0 -9 -2"/>

这个是在正方形的基础上加上

M20,15
            a5,6 -15 0 0 -9,2
            c0,5 4,6 9,12
            c5,-6 9,-7 9,-12
            a5,6 15 0 0 -9 -2

我们看看如果pathData 单独设为上述路径会是什么样的
这里写图片描述

果然很漂亮。首先它从白色的点 (20,15)开始,向逆时针方向,也就是右边画了一段圆弧到蓝色的点(11,17),圆弧所在的椭圆逆时针转15°,取短弧,逆时针。然后再画一条三阶贝塞尔曲线,控制点分别是黄点(11,22),黑点(15,23),终点是绿色的点(20, 29)。这样子就完成了心型的一半了。另一半跟这边的完全对称,也就不细说了。

完整代码

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="40"
        android:viewportHeight="40">

    <path
        android:fillColor="#f24e4e"
        android:pathData="M8,4
        h24 q4,0 4,4 v24 q0,4 -4,4
        h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
        M20,15
        a5,6 -15 0 0 -9,2
        c0,5 4,6 9,12
        c5,-6 9,-7 9,-12
        a5,6 15 0 0 -9 -2"/>

</vector>

<think>好的,用户想了解Android中关于矢量图形的使用和实现。首先,我需要回忆一下Android中处理矢量图形的相关知识。记得Android支持矢量图形主要是通过VectorDrawable来实现的,这样可以避免使用位图在不同分辨率下需要多套资源的麻烦。 首先,应该解释什么是VectorDrawable,以及它的优势。比如,矢量图形基于XML定义,可以缩放而不失真,适合不同屏幕密度。然后需要说明如何在项目中创建和使用VectorDrawable,可能包括在res/drawable目录下创建XML文件,使用<vector>标签等。 接下来,可能涉及到AnimatedVectorDrawable,这是用于给矢量图形添加动画效果的。这里需要举一个例子,比如如何定义一个路径变化的动画,并关联到VectorDrawable上。 然后,实现方面可能需要提到Android的渲染引擎,比如在底层如何将矢量图形转换为GPU可以处理的指令。这里可能需要参考一些系统源码,比如Skia库,因为Android的图形处理很多是基于Skia的,不过用户提供的引用里有提到IAllocator HAL服务和一些源码路径,比如hardware/interfaces/graphics/allocator/2.0/default,这可能与图形内存分配有关,但不确定是否直接关联到矢量图形。不过可以提到系统底层的图形处理服务,如HAL和相关的HIDL接口,比如引用[2]提到的IAllocator HAL服务,可能用于图形内存管理,这对矢量图形的渲染性能可能有影响。 另外,用户提供的引用[3]提到了gl2_basic、gl2_java和angeles相关的源码,可能涉及OpenGL ES的实现,但不确定具体如何与矢量图形关联。可能需要提到Android的图形渲染管线,如使用OpenGL ES或Vulkan来渲染矢量图形,但需要确认准确性。 使用方面,应该包括如何在布局文件中引用VectorDrawable,兼容性问题(因为VectorDrawable在Android 5.0+原生支持,但通过AndroidX库可以支持更低版本),以及性能优化的注意事项,比如复杂路径可能导致渲染性能下降。 可能还需要比较位图和矢量图形的适用场景,矢量图形适合图标、简单图形,而位图适合照片等复杂图像。此外,可以提到SVG到VectorDrawable的转换工具,方便设计师资源导入。 在实现部分,可能需要深入一些系统源码,比如VectorDrawable的解析和渲染流程,但用户提供的引用中没有直接的VectorDrawable源码路径,不过引用[3]提到的gl2_java可能涉及OpenGL的Java层封装,可能和渲染相关,但需要谨慎,避免不准确的信息。 总结回答的结构:先介绍VectorDrawable及其优势,然后是如何创建和使用,包括静态和动画矢量图,接着是兼容性处理,性能优化,最后是底层实现相关的图形系统和可能涉及的HAL服务或底层库,如Skia、IAllocator HAL等。 然后生成相关问题,可能涉及优化技巧、动画实现、兼容性处理、底层渲染机制等。</think>### Android矢量图形使用与实现 #### 一、矢量图形基础 Android通过**VectorDrawable**实现矢量图形支持。矢量图形基于XML定义,使用数学公式描述路径,可无损缩放适配不同屏幕密度[^1]。其核心优势包括: 1. 节省资源:一套XML适配所有分辨率 2. 灵活编辑:通过代码调整图形属性 3. 动画支持:配合AnimatedVectorDrawable实现复杂动画 #### 二、基本使用 1. **创建VectorDrawable** 在`res/drawable/`目录新建XML文件: ```xml <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> <path android:fillColor="#FF0000" android:pathData="M12,2L3,21h18z"/> </vector> ``` 2. **在布局中使用** ```xml <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_vector"/> ``` #### 三、动画实现 通过**AnimatedVectorDrawable**组合矢量图与属性动画: ```xml <!-- animated_vector.xml --> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_vector"> <target android:name="triangle" android:animation="@anim/path_anim"/> </animated-vector> ``` 对应属性动画: ```xml <!-- path_anim.xml --> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:propertyName="pathData" android:duration="1000" android:valueFrom="M12,2L3,21h18z" android:valueTo="M12,20L3,3h18z" android:valueType="pathType"/> ``` #### 四、兼容性处理 1. Android 5.0+(API 21)原生支持 2. 低版本通过AndroidX库兼容: ```gradle dependencies { implementation 'androidx.vectordrawable:vectordrawable:1.1.0' } ``` #### 五、性能优化 1. 限制路径复杂度(建议不超过200条绘制命令) 2. 避免在列表项中过度使用矢量动画 3. 对复杂图形考虑预渲染为位图 #### 六、底层实现 Android矢量图形系统基于以下组件: 1. **Skia图形库**:负责矢量路径的栅格化处理 2. **HAL图形服务**:管理图形内存分配(如引用[2]提到的IAllocator HAL服务) 3. **渲染线程**:通过单独的RenderThread进行离屏渲染 4. **硬件加速**:利用GPU进行路径渲染(引用[3]中提到的GL相关实现可能参与此过程) $$ RenderingPipeline = VectorDrawable \xrightarrow{Parse} SkPath \xrightarrow{Rasterize} GPUCommands $$ #### 七、调试工具 1. **Layout Inspector**:查看矢量图层级结构 2. **GPU渲染模式分析**:检测渲染性能 3. **SVG转换工具**:将Adobe AI/SVG文件转换为VectorDrawable
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值