热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Android使用矢量图(SVG,VectorDrawable)实践篇

前言本文是以读者对SVG有一定了解为前提的,否则请先百(谷)度(歌)了解下。实践都是从坑里爬出来的,因此本文的子题目也可叫做Android使用矢量图填坑记。文章开始前,先墙裂安利一个网站,阿里的ico
前言

本文是以读者对SVG有一定了解为前提的,否则请先百(谷)度(歌)了解下。

实践都是从坑里爬出来的,因此本文的子题目也可叫做Android使用矢量图填坑记。

文章开始前,先墙裂安利一个网站,阿里的iconfont,海量在线矢量图,早收藏早致富。本文主要涉及到的矢量图资源均来自该网站。放图镇楼:

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

<path
android:fillColor="#ffffff"
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>

vector>

基本属性说明:

  • width, height:图片的宽高。可手动修改到需要尺寸;
  • viewportHeight, viewportWidth:对应将上面heightwidth等分的份数。以svg_ic_arrow_right.xml举例,可以想象将长宽都为8dp的正方形均分为24x24的网格,在这个网格中就可以很方便地描述点的坐标,图像就是这些点连接起来构成的。
  • fillColor:填充颜色。最好直接在这里写明色值#xxxxxxxx,而不要用@color/some_color的形式,避免某些5.0以下机型可能会报错。
  • pathData:在2中描述的网格中作画的路径。具体语法不是本文的重点,故不展开。

这段代码描述出来的是一个白色箭头,可以从Android Studio的preview功能栏里预览到它的样子:

android{
...
defaultConfig {
...
vectorDrawables.useSupportLibrary = true
}
...
}
dependencies {
...
compile "com.android.support:appcompat-v7:21+" // 至少Api21
...
}

项目的Activity中都包含(通用做法是在BaseActivity中加):

static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

AppCompatImageView

这是继承自ImageView用于5.0以下加载矢量图的控件,只需要替换srcsrcCompat属性,其它没什么不同。例如:

<android.support.v7.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/svg_ic_arrow_right"/>
  • 如果你的Activity直接或间接继承自AppCompatActivity,当前视图中的ImageView在编译过程中会被自动转为AppCompatImageView(support包中所有含有AppCompat前缀的控件均受相同处理),因而在Activity中通过findViewById()的实例用ImageViewAppCompatActivity接收是没有区别的。
  • 用以上条件的Activity中装载的Fragment,或者通过动态注入(如DialogcontentView)的ImageView,均将被自动转为AppCompatActivity
  • 从xml文件中初始化ImageView并加载矢量图,必须使用AppCompatImageViewsrcCompat属性。
  • ImageView的染色属性tint同样适合矢量图。

TextView

在我的经验中,TextView可以用到矢量图的场景是最多的,主要是设置CompoundDrawable。例如:

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableRight="@drawable/svg_ic_arrow_right"
android:drawablePadding="4dp"
android:text="drawable right"/>

这样设置后,没有任何不适,编译器也不报错,可能你自己运行也没问题。但是!这才是深坑啊。5.0以下某些机型可能会崩溃的。

AppCompatTextView是没有对CompoundDrawable进行适配的,所以需要自己动手才能丰衣足食。简单原理是,判断系统版本如果小于5.0,就用ContextCompat.getDrawable获取到Drawable实例,再setCompoundDrawablesWithIntrinsicBounds

这个部分本人已经做好并开源了,地址:VectorCompatTextView,轻松compile到项目中使用。还特意添加了一个实用功能——tint染色——可以选择是否让图标与文字颜色一样,这样就不必关心xml里的fillColor属性了。用例:

<com.xw.repo.VectorCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_gray_light"
android:gravity="center_vertical"
android:padding="16dp"
android:text="Next"
android:textSize="16sp"
app:drawableRightCompat="@drawable/svg_ic_arrow_right"
app:tintDrawableInTextColor="true"/>

效果:


Tips:
存在这样一种情形,连续两个控件(编号1和2)都来加载同一张svg图,svg的本来颜色是A,控件1将颜色改为了B,控件2也加载这张svg,颜色却变为了B,这应该是Android系统对矢量图的缓存造成的。解决办法是把svg的本来颜色改为B,控件2再改为颜色A。(好绕,不过一般不会遇到)

MenuItem

MenuItem就是在res/menu/目录下通过xml配置的菜单,适用于NavigationViewmenu属性和ActivityonCreateOptionsMenu()注入的选项菜单。

前一阵做了一个小应用叫“简影讯”,发现MenuItem是可以完美支持矢量图的,而且也可以自动跟随文字颜色改变颜色。且看证明:



自适应颜色

简影讯(开源地址:GracefulMovies),是一枚基于Retrofit+RxJava+MVP+Colorful多彩主题框架开发的高颜值影讯app。简约,优雅,精彩,即看即走。欢迎在应用宝或360手机助手下载围观。
该项目除ic_launcher外,所有的图标都是矢量图。
“是时候全面使用矢量图了。”

VectorDrawable 转 Bitmap

自定义View中也可以自由使用矢量图。
首先需要将VectorDrawable 转为 Bitmap,看码:

public Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (Build.VERSION.SDK_INT drawable = (DrawableCompat.wrap(drawable)).mutate();
}

Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);

return bitmap;
}

执行以上方法获得一个Bitmap的实例(设为mVectorBitmap),然后再在ondraw()里根据你的需求画出bitmap:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
///
canvas.drawBitmap(mVectorBitmap, left, top, paint);
///
}

后记

矢量图的优点一大把,但也不是万能的。矢量图特别适合icon图标的应用场景,但是不能用于比如加载相册时,设置的placeholder或者error这类需要频繁切换回收的应用场景,否则会造成非常明显的卡顿,因为矢量图是不被硬件加速支持的。

Android 5.0推出已经有些年份了,也不知道Android开发圈对矢量图的使用情况,但知道比如微信这些大厂早已全面推广使用。然而在本人周边似乎自己算先驱了,所以才有了把过程中的一些经验总结分享出来的想法。

毕竟本人才疏学浅,难免有纰漏之处,请大神轻拍砖,并不吝赐教。若对后来学习者有帮助,那花这一天码的字自然也超值了,希望共勉。


转载自:
作者:woxingxiao
链接:http://www.jianshu.com/p/0555b8c1d26a
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

推荐阅读
author-avatar
青峰的兔子饭团
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有