矢量图也称为面向对象的图像或绘图图像,是根据几何特性来绘制的图形,在安卓开发中可以使用失量图代替原来的图片资源,矢量图具有占用空间小和可以随意缩放但不失真的优势,在我的多个项目中都有运用。
通过学习和实践,我总结了一些与矢量图相关的知识,方便今后更好的使用矢量图,同时也可以供大家查阅参考。
绘制矢量图之前需要先定义画布的宽高,后续的绘制效果都展示在这个画布上。在绘制过程中需要输入的坐标就是这个画布上的点。
安卓的矢量图常见于 drawable 文件夹下,是一个xml文件,由 vector 标签包裹,在 vector 标签中可包含多个 path 标签,依次叠加显示。
在矢量图中最重要的就是 path 属性,图像的样式就是由 path 属性中的数据绘制而成,这些数据由不同的命令组合而成,下面就介绍一些矢量图的绘制命令。
将前面的命令示例连接起来就可以生成一个完整的图像,它大概长这个样子:
画布的尺寸为500x500,图上的顶点是200,10的位置,也是我们开始作图的起点。通过这个图片可以更好的理解每一个绘图命令。
安卓中可以为矢量图添加动画效果,这样用户就可以看到一个动的图片,可以一定程度的提高app的交互效果。矢量图动画是图形内部的变化,可以做到View动画无法实现的效果。
这种动画针对的是矢量图中 path 字段的值,通过连续改变 path 字段的值而达到产生动画的效果。
注:pathData动画所需的AnimatedVectorDrawable最低要求API等级为25
实现一个矢量图动画需要以下几步:
1. 准备起始状态和结束状态的矢量图两张。
2. 创建动画配置文件。
3. 创建动画矢量图文件。
4. 启动动画。
基于这种要求,我准备了两个矢量图:
控制动画运行的是一个 objectAnimator ,此处把 objectAnimator 包裹在一个 set 中也是可以的,说白了就是执行这个动画文件。
duration 用来指定动画的持续时间。
propertyName 中的pathData指的就是矢量图中的pathData。
valueFrom 和 valueTo 一个是起始路径,一个是结束路径,可以想到,这个动画就是在持续修改pathData,从而达到展示动画的效果。而 valueFrom 和 valueTo 的值是直接从先前准备的矢量图中复制过来的,所以那个结束状态的矢量图中唯一有用的东西就是pathData属性,没有那个文件也无所谓。
valueType 这里必须填写pathType,这是专门用来计算path的类型。
此时,文件的最外层由 animated-vector 包裹,同时需要添加一个 drawable 参数,这个 drawable 用于指定动画应用于那个矢量图上,我们是要从未启用状态变成启用状态,所以是在未启用状态开始执行动画,在动画未开始的时候展示的也是未启用状态。此处我们指定为 @drawable/icon_filter_off 。
内部有一个 target 标签,这个标签可以有多个,分别对应不同的动画,但同一个 path 只能应用一个动画。
name 用于指定要执行动画的 path 。status正是我们为右下角小图标path设置的名称。
animation 用于指定需要执行的动画。此处引用我们刚刚创建的动画资源 @animator/filter_turn_on 。
当我们创建好动画矢量图之后,页面中引用的资源就不再是之前的静态矢量图了,需要把 ImageView 的图片替换成 @drawable/animated_filter_on
经过这么多的步骤,我们终于做出了一个矢量图动画,而且是一个。说实话,有点累,然而我这个状态切换的动画一套就要两个,所以我又加了一个回来的动画和对应的动画矢量图,一共六个文件,完成了筛选状态的两个切换动画。这还是比较简单的实现方式,对于两种状态切换的动画,网上还有一种使用selector的方式,这种方式更麻烦,而且使用方法并没有简单一些,所以我的选择是在需要切换状态的时候更改 ImageView 的图片资源,然后再执行动画。
trimPath动画相当于是改变了矢量图绘制的位置,是从头开始画还是从80%的位置开始画,然后再动态的修改这个百分比,从而达到动画的效果。理解起来倒不是很难。
先放一个我使用trimPath动画做的loading效果,这个动画效果被我用在LoadingDialog中,在界面加载的时候会重复播放这个动画。
android:name="load" 不用多说,这个是我们做动画时路径名称。这里为了让心电图路径更清晰,我设置了描边宽度为20( android:strokeWidth="20" ),同时还要设置描边的颜色才能展示出来。后面的 android:trimPathStart="0" 和 android:trimPathEnd="0" 是本次trimPath动画的重点。
这两个属性都设置为0是因为动画的起始帧都为0,然后通过 objectAnimator 慢慢把这两个属性变为1,这样一个慢慢增长的动画就形成了。
网络上一个横线变成搜索按钮的示例是将这两个属性分别应用到了两个 path 上,而我是将两个属性同时应用到一个 path 上,原理都是一样的。
在配置文件中,我将两个动画都设置为3秒且循环播放,起始点的动画慢于终点的动画1秒,达到只画中间1秒间隔线段的效果。和路径变形动画的区别是 android:valueType="floatType" ,我们只需要计算从0到1的数字,然后应用到 trimPathStart 和 trimPathEnd 字段上。至此,loading的动画就配置完了。
这一步已经没什么可说的了,就是将指定的矢量图中指定的路径设置一个指定的动画。
通过几天的学习,已经大致掌握了矢量图的展示及动画的制作,但这一套流程下来成本比较高,是程序员方式的动画制作流程。除了制作成本,创意成本也是相当高的,一个好的创意能极大的提升用户体验,而好多时候我们的创意能够被实现也是很困难的。希望以后能实现一些更好的效果,让用户使用起来更舒服。
SVG—最简单的SVG动画
SVG路径(path)中的圆弧(A)指令的语法说明及计算逻辑
Android中的矢量图
Android高级动画(2)
安卓手机如何打开.ai文件?
从5.0(API等级21)开始,android开始支持矢量图了。关于什么是矢量图以及矢量图有什么优缺点不在本文的涉及范围之内,具体可以参考矢量图百科。不过这里要提一下它的优点:
保存最少的信息,文件大小比位图要小,并且文件大小与物体的大小无关
任意放大矢量图形,不会丢失细节或影响清晰度,因为矢量图形是与分辨率无关的。
从以上两个优点来看,在项目中使用矢量图至少可以缩小我们apk包的尺寸,而且可以在屏幕适配时提供很大的方便,因为矢量图是分辨率无关的。
前面也说了,矢量图从21才开始支持。那么如果我想往下兼容改怎么办呢?这个问题要放在以前的话,我会说github下就有你要的答案。但现在我不会这么说,因为前段时间Google升级了support library,官方向后兼容了矢量图的使用。要问兼容到哪个版本,我告诉你矢量图兼容到API7,矢量图动画兼容到API11(是不是已经满足了你的使用)。
好了,下面我们就来说说怎么在项目中使用矢量图。
一、VectorDrawable的使用
按照官方的说法,要在低版本上使用矢量图,需要在项目中引入新的兼容库support-vector-drawable,并且appcompat-v7库的版本要在23.2.0+(写文章这会23.2.1已经发布了)。而且你还要修改下gradle的相关配置,不要让gradle在构建的时候为你在低版本(API21以下)的情况下生成针对于不同密度的png文件,因为android studio1.4的时候支持了矢量图。
修改appcompat-v7的版本
compile 'com.android.support:appcompat-v7:23.2.0'
NOTE: 这里我只引入了23.2.0版本的appcompat-v7库,同步gradle后就编译出了support-vector-drawable-23.2.0和animated-vector-drawable-23.2.0这两个库。
修改gradle配置文件
如果你的gradle插件的版本为2.0以下,你应该这么修改
android {
defaultConfig {
// 不让gradle自动生成不同屏幕分辨率的png图
generatedDensities = []
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
如果你的gradle插件版本是2.0+,你 应该这么修改
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
经过上面这几步的修改,你就可以在项目中使用矢量图了。那么,下面我们就正式来说说怎么使用。
android studio为我们提供了一个Vector Asset Studio的工具,让我么可以从material icon和svg文件生成矢量图。具体用法可以参考官方的说明文档,这里就不多说了。
Android中矢量图是以xml文档的形式存在的,像下面这样就定义了一个矢量图,里面包含了关于该矢量图的数据信息。
<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z" />
</vector>
这是我通过material icon生成的,它在android中对应着VectorDrawable这个类,也就是兼容包中的VectorDrawableCompat这个类。
定义好矢量图形后,我们就可以向普通的图形那样来使用它了。不过有几点需要注意:
*使用android:src属性的地方需要替换为app:srcCompat属性
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.damon.vectordrawabledemo.MainActivity">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_mood_black_24dp" />
</RelativeLayout>
*在非src属性的地方使用矢量图时,需要将矢量图用drawable容器(如StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable, 和RotateDrawable)包裹起来使用。否则会在低版本的情况下报错。
而在代码中的使用和普通的png图没什么区别,调用的是同样的API。
为什么安卓开发不支持矢量图标素材
先把ai格式图片放入手机文件夹,然后打开Ai viewer软件。在手机的文件夹中找到ai文件,点击打开。双指捏合,那么即可在手机打开ai文件。退出软件的,点击home,关闭进程即可。先安装Ai viewer的软件,然后打开文件管理。找到ai文件的位置,然后此时打开软件。然后点击浏览,选择ai文件所在目录。点击ai文件,那么即可手机上预览。要转换ai文件,那么点击软件右上角,点击转换。就可以转换成了,转换后的文件,可以分享。AI是Adobe Illustrator的文件扩展名,是一种矢量图形文件格式。Adobe Illustrator是一种流行的基于矢量图形的绘图程序。AI格式是一个严格限制的,高度简化的EPS子集。AI代表Adobe Illustrator。为打开.ai文件,可以使用与photoshop软件同属Adobe公司的illustrator软件。在正常的情况下.ai文件也可以通过photoshop打开,但打开后的图片就只是位图而非矢量图,并且背景层是透明的。至于打开后的精度,可以在打开时弹出的对话框上修改图片的分辨率。ai文件也可以直接用Acrobat阅读器打开,但仅限于查看。
如何使用Android的VectorDrawable类绘制矢量图
安卓开发不支持矢量图原因:
基于Android L深度定制研发的乐视手机EUI很多图标都已经使用这样的方式提供资源,以更方便的兼容1080p与2K屏幕。
现在很多Android应用使用位图资源的原因应该是仍然要兼容低版本的Android系统。未来使用SVG / XML矢量资源的应用可能会越来越多。
矢量图的显示,实际上还是需要图像引擎将数学曲线格栅化成位图,然后才能在屏幕上呈现。与使用位图相比,多了一层计算,自然有性能上的消耗。
使用矢量图可能还有 pixel-perfection 的问题。虽然矢量图亦可以通过对齐网格做到 pixel-perfect(比如 OS X 也有系统 App 使用了 PDF 来绘制一些小图标),但若要通过矢量图实现解决缩放的问题,势必会有非整数倍放大 / 缩小的情况。
矢量图在非整数倍数渲染时,则很可能会出现虚边。若渲染时强制对齐网格,效果亦未必好。
UI 设计矢量化在安卓开发设计还是大势所趋的。
1. 创建Vector Drawable
从相似角度来看,VectorDrawable与标准SVG图形都是利用path值绘制完成的。不过如何利用SVG path绘制图形并不在本篇文章的探讨范围之内,大家可以点击此处从W3C网站处获取必要的说明资料。在本文当中,我们只需要了解到path标签的作用是进行图形绘制即可。让我们首先从SVG文件入手,看看以下图形是如何被绘制出来的:
这一图形共由五个主要部分所组成:
一个圆角四边形作为CPU主体,该四边形由两条拱状弧线构成。
四组各自包含五根线条的图形,用于充当CPU的外延线路。
虽然看起来有点繁杂,但大家其实用不着纠结于以上代码的具体含义,而且这完全不会影响到我们接下来要进行的VectorDrawable绘制工作。不过需要强调的是,我将前面提到的五大图形组成部分在代码中作为独立的区块来处理,这是为了增强代码内容的可读性。
首先,我们需要利用两条拱形弧线来绘制出圆角四边形,而在接下来的内容中我们会探讨如何分别表现出上、下、左、右四个方位的外延线条。为了将上述SVG代码转化为VectorDrawable,大家首先需要在XML当中定义vector对象。以下代码提取自本篇文章示例代码当中的vector_drawable_cpu.xml文件。
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" android:width="64dp" android:viewportHeight="600" android:viewportWidth="600" > </vector>
在此之后,大家可以向其中添加path数据。下列代码同样被拆分成了五个不同的path标签而非将其作为整体处理,这当然也是为了保证内容的可读性。
正如大家所见,每个path片段都只需要利用pathData属性进行绘制。现在我们可以将VectorDrawable XML文件作为一个可绘制对象纳入到标准ImageView当中,而且其能够根据应用程序的实际需要任意进行尺寸缩放——完全不需要再修改任何Java代码。
2. 为Vector Drawables添加动画效果
现在我们已经了解了如何以纯代码方式创建图形,接下来要做的是找点乐子——为其添加动画效果。在以下动画中,大家会发现作为延伸线路的各组线条会不断指向并远离CPU本体进行移动。
为了达到这一目标,大家需要将包含动画效果的每个片段包含在一个<group>标签当中。
接下来,我们需要为每个动画类型创建animator文件。在本次示例中,每组线路各使用一个animator,这就意味着共需要四个animator。以下代码所示为上方线路的动画效果,大家还需要为下、左、右线路设定类似的效果。每个animator XML文件都被包含在了本项目的示例代码当中。
如大家所见,propertyName被设定为translateY,这意味着该动画将沿Y轴方向移动。而valueFrom与valueTo则控制着位移的起点与终点。通过将repeatMode设置为reverse而repeatCount设置为infinite,整个动画会一直循环下去,其效果则在VectorDrawable处体现出来。该动画的duration被设定为250,其时长单位为毫秒。
为了将该动画应用到自己的可绘制文件当中,大家需要创建一个新的animated-vector XML文件,从而将这些animator分配给各VectorDrawable组。以下代码的作用是创建该animated_cpu.xml文件。
<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_drawable_cpu"> <target android:animation="@animator/pulse_top" android:name="top" /> <target android:animation="@animator/pulse_right" android:name="right" /> <target android:animation="@animator/pulse_left" android:name="left" /> <target android:animation="@animator/pulse_bottom" android:name="bottom" /></animated-vector>
当所有必要的XML文件都已经准备完成后,大家就可以将animated_cpu.xml加入到ImageView当中进行显示了。
<ImageView android:id="@+id/cpu" android:layout_width="64dp" android:layout_height="64dp" android:src="@drawable/animated_cpu" />
要开始播放动画效果,大家需要从ImageView当中获取Animatable实例并调用start。
ImageView mCpuImageView = (ImageView) findViewById( R.id.cpu )Drawable drawable = mCpuImageView.getDrawable()if (drawable instanceof Animatable) { ((Animatable) drawable).start()}
在start被调用之后,CPU图形当中的线路图形就会开始移动——整个过程只需要使用少量Java代码即可实现。
3. Vector Drawables的变化方式
对于VectorDrawable来说,最常见的一种使用方式就是将一个图形转化至另一个图形,例如操作栏中的图标由汉堡变成箭头。要做到这一点,源与目标path二者都必须具备同样的格式以保证元素数量上的一致。在本次示例中,我们将如前文图片所示尝试将左箭头转化为右箭头。
<string name="left_arrow">M300,70 l 0,70 -70,-70 0,0 70,-70z</string> <string name="right_arrow">M300,70 l 0,-70 70,70 0,0 -70,70z</string>
接下来,大家需要利用path为left_arrow建立一个初始drawable。在示例代码中,我们将其命名为vector_drawable_left_arrow.xml。
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:height="64dp"android:width="64dp"android:viewportHeight="600"android:viewportWidth="600" ><pathandroid:name="left_arrow"android:fillColor="#000000"android:pathData="@string/left_arrow"/>/vector>
CPU动画与这里提到的图形变化示例之间,最主要的区别就体现在animator_left_right_arrow.xml文件当中。
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:duration="1000" android:propertyName="pathData" android:valueFrom="@string/left_arrow" android:valueTo="@string/right_arrow" android:valueType="pathType" android:repeatMode="reverse" android:repeatCount="-1"/> </set>
大家可能已经注意到了,valueFrom与valueTo两项属性会引用左箭头与右箭头的path数据,valueType被设定为pathType而propertyName则被设定为pathData。当以上设定完成之后,该animator将明确如何将一组path数据转化为另一组。当该animator结束之后,我们还需要利用新的animated-vector对象将VectorDrawable分配至objectAnimator。
<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_drawable_left_arrow"> <target android:name="left_arrow" android:animation="@animator/animator_left_right_arrows" /></animated-vector>
最后,大家还需要将该动画drawable分配至ImageView,而后在自己的Java代码中开始运行。
<ImageView
android:id="@+id/left_right_arrow"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_below="@+id/cpu"
android:src="@drawable/animated_arrow" />
mArrowImageView = (ImageView) findViewById( R.id.left_right_arrow )
drawable = mArrowImageView.getDrawable()
if (drawable instanceof Animatable) {
((Animatable) drawable).start()
}
以上就是关于安卓开发中矢量图的绘制及动画全部的内容,如果了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!