SVG和Vector的概念和如何在Android Studio中使用

    今天我在看某脑SVG视频和网上查资料时,发现了和某位大佬的写文章的某种巧合(报以微妙的笑容)。因为强迫症,所以我想总结性的抄袭一下。不论是否被发现,一切荣誉归属于大佬。
    抄袭对象大佬: Android Vector曲折的兼容之路

引导:

Android微信上的SVG

概念

SVG

    即Scalable Vector Graphics 可伸缩矢量图形,这种图像格式在前端中已经使用的非常广泛了。详见WIKI:https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
    什么是矢量图像,什么是位图图像?
- 矢量图像:SVG是W3C 推出的一种开放标准的文本式矢量图形描述语言,他是基于XML的、专门为网络而设计的图像格式,SVG是一种采用XML来描述二维图形的语言,所以它可以直接打开xml文件来修改和编辑。
- 位图图像:位图图像的存储单位是图像上每一点的像素值,因而文件会比较大,像GIF、JPEG、PNG等都是位图图像格式。
    在android开发中,不能直接使用SVG文件作为图片文件,否则就会这样:
不能直接复制svg文件到as里
    这个时候,我们就需要用到Vector。

Vector

    在Android中指的是Vector Drawable,也就是Android中的矢量图,可以说Vector就是Android中的SVG实现(并不是支持全部的SVG语法,现已支持的完全足够用了)详见:https://developer.android.com/reference/android/graphics/drawable/VectorDrawable.html
    补充:Vector图像刚发布的时候,是只支持Android 5.0+的,但是在之后,谷歌进行了兼容:
1. Gradle Plugin 1.5的兼容
    从Gradle Plugin 1.5开始,Google支持了一种兼容方式,即在Android L之上,使用Vector,而在L之下,则使用Gradle将Vector生成PNG图像。
    Android gradle plugin 1.5发布以后,加入了一个跟VectorDrawable有关的新功能。Android build tools 提供了另外一种解决兼容性的方案,如果编译的版本是5.0之前的版本,那么build tools 会把VectorDrawable生成对应的png图片,这样在5.0以下的版本则使用的是生成的png图,而在5.0以上的版本中则使用VectorDrawable.在build.gradle添加generatedDensities配置,可以配置生成的png图片的密度。
2. AppCompat23.2的兼容
    从com.android.support:appcompat-v7的版本为23.2.0起,Vector可以兼容到Android 2.1以上的所有系统,只需要

 compile 'com.android.support:appcompat-v7:23.2.0'//及以上

    23.2.0及以上的版本就可以了。
     注意事项:所谓的兼容并非能够使用SVG了,本质还是生成了PNG图片来使用。
不同版本的本质

Vector Drawable:

    Android 5.0发布的时候,Google提供了Vector的支持,即:Vector Drawable类。
    Vector Drawable相对于普通的Drawable来说,有以下几个好处:
- Vector图像可以自动进行适配,不需要通过分辨率来设置不同的图片,这在我眼里是最好的地方。
- Vector图像可以大幅减少图像的体积,同样一张图,用Vector来实现,可能只有PNG的几十分之一,这从减少apk大小上很有意义,但有大佬发现,其实并不是完全就能减少,当PNG只有十几k,用Vector反而变大了。
- 使用简单,很多设计工具如PhotoShop、Illustrator,都可以直接导出SVG图像,从而转换成Vector图像,够灵活,不用写很多代码就可以实现非常复杂的动画。
- 成熟、稳定,前端已经非常广泛的进行使用了。

Vector 语法简介

    Android以一种简化的方式对SVG进行了兼容,这种方式就是通过使用它的Path标签,通过Path标签,几乎可以实现SVG中的其它所有标签,虽然可能会复杂一点,但这些东西都是可以通过工具来完成的,所以,不用担心写起来会很复杂。
- Path指令解析如下所示:

M = moveto(M X,Y) :将画笔移动到指定的坐标位置,相当于 android Path 里的moveTo()
L = lineto(L X,Y) :画直线到指定的坐标位置,相当于 android Path 里的lineTo()
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 curveto(T ENDX,ENDY):映射 同样二次贝塞尔曲线,更平滑 
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线 ,相当于arcTo()
Z = closepath():关闭路径(会自动绘制链接起点和终点)
  • 使用原则:
    1. 坐标轴为以(0,0)为中心,X轴水平向右,Y轴水平向下
    2. 所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系
    3. 指令和数据间的空格可以省略
    4. 同一指令出现多次可以只用一个

    注意事项
1. ’M’处理时,只是移动了画笔, 没有画任何东西。
2. 关于这些语法,开发者不需要全部精通,而是能够看懂即可,这些path标签及数据生成都可以交给美工工具和网上的网站来实现:
    1)可以使用SVG的编辑器来进行SVG图像的编写,例如:http://editor.method.ac/
SVG图像的编写
    2)有些网站可以找到SVG资源
    SVG下载地址: http://www.shejidaren.com/8000-flat-icons.html
http://www.flaticon.com/
    阿里的iconfont :http://www.iconfont.cn/home/index?spm=a313x.7781069.1998910419.1
我个人喜欢后面那个。
    3)对SVG文件用http://inloop.github.io/svg2android/ 生成 VectorDrawable xml代码
上传图片文件到网站里
自动生成Vector的xml文件
    4)使用Android Studio自带功能Vector Asset Studio,完成SVG添加,将SVG文件转成Vector。
阿里的iconfont下载svg文件1
阿里的iconfont下载svg文件2
image.png
阿里的iconfont下载的svg文件
as里选择Vector Asset
选择生成可用文件方式
选择生成可用文件所在位置
生成成功,查看效果
    补充:也可参考网址http://www.jianshu.com/p/d6c39f2dd5e7

静态Vector图像

  1. 生成图片
        例如: 我们用as生成一个矩形
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="200dp"
        android:height="200dp"
        android:viewportHeight="500"
        android:viewportWidth="500">

    <path
        android:name="square"
        android:fillColor="#000000"
        android:pathData="M100,100 L400,100 L400,400 L100,400 z"/>
</vector>

矩形
    解释头部的几个标签:
    android:width /android:height:定义图片的宽高
    android:viewportHeight / android:viewportWidth:定义图像被划分的比例大小,例如例子中的500,即把200dp大小的图像划分成500份,后面Path标签中的坐标,就全部使用的是这里划分后的坐标系统。
    这样做有一个非常好的作用,就是将图像大小与图像分离,后面可以随意修改图像大小,而不需要修改PathData中的坐标。
2. 在控件中使用
 - 使用ImageView,就当普通的图片使用就可以了。

            <ImageView
                android:id="@+id/iv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:srcCompat="@drawable/vector_image"/>

    或者代码设置:

                ImageView iv = (ImageView) findViewById(R.id.iv);
                iv.setImageResource(R.drawable.vector_image);
                iv.setBackgroundResource(R.drawable.vector_image);//setBackgroundResource也是可以设置Vector的API

    注意事项
1. 当我的minSdkVersion 小于21时,不在5.0+,则不能对Vector直接使用app:srcCompat,否则会报错,需要去build.gradle里去设置一下。后面会在兼容里讲【1】。如果是minSdkVersion>=21,当然是不会报错的了。
需build里设置
2. 使用的都是普通的ImageView,而没有改成AppcomatImageView,这是因为使用了Appcomat后,系统会自动把ImageView转换为AppcomatImageView。

  • 如果是Button,则不能直接使用app:srcCompat来直接使用Vector图像,需要通过Selector来进行使用,首先,创建两个图像,用于Selector的两个状态(写两个SVG的Drawable):
                <?xml version="1.0" encoding="utf-8"?>
                <selector xmlns:android="http://schemas.android.com/apk/res/android">
                    <item android:drawable="@drawable/selector1" android:state_pressed="true"/>
                    <item android:drawable="@drawable/selector2"/>
                </selector> 

    非常简单,只是把普通的Selector中的图像换成了Vector图像而已,接下来,在Button中使用这个Selector即可:

<Button
    android:id="@+id/btn"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:background="@drawable/selector"/>

    然后运行时又会发现有个兼容的坑,也在下面讲【2】。

动态Vector

    动态Vector才是Android Vector Drawable的重点。
    动态的Vector需要通过animated-vector标签来进行实现,它就像一个粘合剂,将控件与Vector图像粘合在了一起,一个基础的animated-vector代码如下所示:

<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/XXXXX1">

    <target
        android:name="left"
        android:animation="@animator/XXXXX2"/>

</animated-vector>

    举例:
一开始为勾,后为叉的效果

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
                 android:drawable="@drawable/path_tick" >
    <target
        android:name="tickCrossGroup"
        android:animation="@animator/anim_path_tick2cross" />
</animated-vector>

    设置了初始显示时的“path_tick”Vector图像,然后,target目标是最终达到“anim_path_tick2cross”效果。
    注意事项
animated-vector注意事项
    animated-vector在Android Studio中实际上是会报错的,但这个并不影响编译和运行,属于Android Studio的Bug。
path_tick
    path_tick代码为:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:height="120dp"
        android:width="120dp"
        android:viewportWidth="24"
        android:viewportHeight="24">
    <group>
        <path
            android:name="tickCrossGroup"
            android:pathData="M19.6,7 L10.4,16.2 M4.8,13.4 L9,17.6"
            android:strokeColor="#000"
            android:strokeWidth="2"/>
    </group>
</vector>

    path_tick是目标Vector图像,也就是静态的Vector图像。
    可以发现,这里的Vector图像有个group标签。group标签的作用有两个:
- 对Path进行分组,由于我们后面需要针对Path进行动画,所以可以让具有同样动画效果的Path在同一个Group中。
- 拓展动画效果,单个的path标签是没有translateX和translateY属性的,因此无法使用属性动画来控制path translateY,而group标签是有的,所以我们需要先将相关的path标签元素包裹在一个个的group标签中。
    anim_path_tick2cross代码为为:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="300"
        android:propertyName="pathData"
        android:valueFrom="M19.6,7 L10.4,16.2 M4.8,13.4 L9,17.6"
        android:valueTo="M17.6,6.4 L6.4,17.6 M6.4,6.4 L17.6,17.6"
        android:valueType="pathType"/>
</set>

    anim_path_tick2cross实际上就是利用属性动画来实现的动画效果。
    android:propertyName属性名,上文里为pathData,指的是path_tick里的

 android:pathData="M19.6,7 L10.4,16.2 M4.8,13.4 L9,17.6"

    从 android:valueFrom动画效果到 android:valueTo。
    当然,也可以android:propertyName=”translationX”这样换别的动画属性。
写好了动态Vector,作为动画,肯定是要开启执行动画。怎么搞?

  <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="anim"
            app:srcCompat="@drawable/path_tick2cross_anim"/>
 public void anim(View view) {
ImageView imageView = (ImageView) view;
AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(this, R.drawable.path_tick2cross_anim);
imageView.setImageDrawable(animatedVectorDrawableCompat);
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof Animatable) {
            ((Animatable) drawable).start();
        }
    }

    判断imageView的图片是个动图,即属于Animatable,则强转并启动动画。这样不再需要动态写代码动画来搞了,向美工御姐撒撒娇就好了。
    注意事项 :如果是两个SVG进行动画,path元素中从一个形状转变到另一个形状,这两个形状必须满足:要有一致的命令(command)个数(逗号分割开的为命令),并且每个命令的参数个数也必须一致。

版本兼容

    VectorDrawableCompat依赖于AAPT的一些功能,它能保持最近矢量图使用的添加的属性ID,以便他们可以在L版本之前被引用。
    在Android 5.0之前使用Vector,需要aapt来对资源进行一些处理,这一过程可以在aapt的配置中进行设置,如果没有启用这样一个flag,那么在5.0以下的设备上运行就会发生android.content.res.Resources$NotFoundException。
1. 最重要的是添加appcompat的支持,如:

compile 'com.android.support:appcompat-v7:25.3.1'

    同时,确保你使用的是AppCompatActivity而不是普通的Activity。
2. 你需要在项目的build.gradle脚本中,增加对Vector兼容性的支持,代码如下所示:
    使用Gradle Plugin 2.0以上:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

    使用Gradle Plugin 2.0以下,Gradle Plugin 1.5以上:

android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag to tell aapt to keep the attribute ids around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }

    这种兼容方式实际上是先关闭AAPT对pre-L版本使用Vector的妥协,即在L版本以上,使用Vector,而在L版本前,使用Gradle生成相应的PNG图片,generatedDensities这个数组,实际上就是要生成PNG的图片分辨率的数组,使用appcompat后就不需要这样了。
L版本的前后
    这就是解决了【1】的问题。
3. 版本不同,对DrawableContainers兼容性问题
    Google的一位开发者在博客中写到:

First up, this functionality was originally released in 23.2.0, but then we found some memory usage and Configuration updating issues so we it removed in 23.3.0. In 23.4.0 (technically a fix release) we’ve re-added the same functionality but behind a flag which you need to manually enable.

    实际上,他们的这个改动,就影响了类似DrawableContainers(DrawableContainers which reference other drawables resources which contain only a vector resource)这样的类,它的一个典型,就是Selector(StateListDrawable也是)。这个开发者在文中提到的flag,就是下面的这段代码,放在Activity的前面就可以了:

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

    开启这个flag后,你就可以正常使用Selector这样的DrawableContainers了。同时,你还开启了类似android:drawableLeft这样的compound drawable的使用权限,以及RadioButton的使用权限,以及ImageView的src属性。
    这就是解决了【2】的问题。
4. 动态Vector动画兼容性问题
    1) 向下兼容问题
    一说到兼容,就不得不提到坑,几乎所有的为了兼容而做的改动,都会留下一些不可填满的坑,动态Vector动画也不例外,虽然Google已经对Vector图像进行了Android 2.1以上的兼容,但对于动态Vector动画,还是有很多限制的,例如:
    Path Morphing,即路径变换动画,在Android pre-L版本下是无法使用的。
     Path Interpolation,即路径插值器,在Android pre-L版本只能使用系统的插值器,不能自定义。
    Path Animation,即路径动画,这个一般使用贝塞尔曲线来代替,所以没有太大影响。
    2) 向上兼容问题
    除了在低版本上的兼容性问题,在L版本以上,也存在兼容性问题,即继承了AppCompatActivity的界面,如果直接设置ImageView的srcCompat,那么Path Morphing动画是无法生效的,因为默认的AppCompatActivity已经默认使用ImageViewCompat给转换了,但是AnimatedVectorDrawableCompat是不支持Path Morphing动画的,所以,在AppCompatActivity界面里面就无效了。
    解决办法很简单,即使用代码来给ImageView添加动画:

 ImageView imageView = (ImageView) view;
        AnimatedVectorDrawable morphing = (AnimatedVectorDrawable) getDrawable(morphing);
        imageView.setImageDrawable(morphing);
        if (morphing != null) {
            morphing.start();
        }

    注意:不要使用AnimatedVectorDrawableCompat即可。
5. 抽取string兼容问题
    开发者有时候为了代码简洁可能会把Vector图像中的pathData放到string.xml中,然后在Vector图像中引用string。
    但这种方式如果通过生成png来兼容5.0以下机型的话,会报pathData错误,编译器不会去读取string.xml,只能把pathData写到Vector图像中,动画文件中也是一样。
6. 其它兼容问题
    其它非常奇怪、诡异、不能理解的兼容性问题,只能通过版本文件夹的方式来进行兼容了,例如drawable-v21和drawable,分别创建两个文件名相同的资源在两个文件夹下,这样在21以上版本,会使用drawable-v21的资源,而其它会使用drawable下的资源。
7. 即时有了兼容方式,但是,还是会有一些Vector动画是不能兼容Android pre-L版本的,只能兼容L+。

学习Vector

    大佬的Vector动画Demo库,地址如下所示:
https://github.com/xuyisheng/VectorDemo
    这个Demo分为两部分,一部分是可以兼容Android pre-L版本和L+版本的Vector动画,另一部分(通过Actionbar的按钮切换)是只能兼容L+的Vector动画。
    注意事项:这个能兼容和不能兼容,是因为Vector动画本身的效果不能在pre-L版本兼容。不是代码没设置。
    每个Vector动画,基本都包含四部分内容,即:

Vector:图像资源
Animated-vector:动画、图像粘合剂
ObjectAnimator:动画资源
代码:启动动画

每个Vector动画通过这四个部分去进行分析,就非常清晰了。
    这里展示下Demo的效果图:
Demo

VectorDrawable的性能问题:

  • Bitmap的绘制效率并不一定会比Vector高,它们有一定的平衡点,当Vector比较简单时,其效率是一定比Bitmap高的,所以,为了保证Vector的高效率,Vector需要更加简单,PathData更加标准、精简,当Vector图像变得非常复杂时,就需要使用Bitmap来代替了
  • Vector适用于ICON、Button、ImageView的图标等小的ICON,或者是需要的动画效果,由于Bitmap在GPU中有缓存功能,而Vector并没有,所以Vector图像不能做频繁的重绘
  • Vector图像过于复杂时,不仅仅要注意绘制效率,初始化效率也是需要考虑的重要因素

参考

https://www.youtube.com/watch?v=wlFVIIstKmA&feature=youtu.be&t=6m3s
https://medium.com/@shemag8/animated-vector-drawable-e4d7743d372c#.3vkt12j20 https://github.com/jpuderer/AnimatedButton
Android vector标签 PathData 画图超详解
 Android Vector曲折的兼容之路

有个加急项目来了,所以留待以后再更进一步研究。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AndroidVector Asset Studio是一个用于创建和管理矢量图标的工具。它可以帮助开发者在应用程序使用矢量图标,而无需担心图标在不同屏幕密度下的模糊或失真问题。 要使用Vector Asset Studio,首先需要打开Android Studio,并确保已经创建了一个Android项目。然后,按照以下步骤进行操作: 1. 在Android Studio的项目视图,右键单击res文件夹,选择"New" -> "Vector Asset"。 2. 在弹出的向导,选择要导入的矢量图标类型。可以选择从Material Design图标库导入,也可以选择从本地文件系统导入。 3. 如果选择从Material Design图标库导入,可以在搜索框输入关键字来查找所需的图标。选择图标后,可以预览并调整其大小和颜色。 4. 如果选择从本地文件系统导入,可以点击"Local file"按钮,然后选择要导入的SVG或者AI文件。导入后,可以预览并调整其大小和颜色。 5. 在预览窗口,可以通过调整大小和颜色来自定义图标。还可以选择生成的资源类型(如Drawable或Mipmap)以及目标密度。 6. 完成自定义后,点击"Next"按钮,然后选择要生成的资源文件夹和文件名。点击"Finish"按钮完成导入过程。 完成上述步骤后,Android Studio将自动生成相应的矢量图标资源文件,并将其添加到项目。可以在布局文件或代码使用这些矢量图标资源,就像使用其他Drawable资源一样。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值