美文网首页大智收藏Android UIAndroid
关于android中矢量图如何用,有坑,爬坑,如何替代的另一些看

关于android中矢量图如何用,有坑,爬坑,如何替代的另一些看

作者: a帆仔 | 来源:发表于2016-05-21 21:22 被阅读7479次

    在安卓的发展历程中,由于设备碎片化的原故,谷歌在app中图标的适配上做出一步又一步的改进,大体有这么几个阶段:
    <ol>
    <li>首先有了drawable-(m|h|xh|xxh|xxxh)dpi</li>
    <li>自android studio后,又有了mipmap-(m|h|xh|xxh|xxxh)dpi</li>
    <li>随着android L的发布,带来了VectorDrawable,矢量图的支持</li>
    </ol>
    第一种方案大家都很熟悉, 但也是我们头痛的地方,因为每种icon都需要出几套不同分辨率,这无形的增加了app的容量,而且也增加了美工和开发人员的工作量,但是我们又不得不去做。
    第二种是第一种的升级版, 没有实质上的区别,但是在缩放上提供了更好的性能和更少的内存占用。
    第三种,矢量图,先大概解释下:矢量图在很久很久以前就已经应用起来了,是一种基于xml的图像,因为图片不提供具体的像素,只提供的是绘图的指令,所以好处是 占用内存非常小,性能高,可以任意缩放而不会失真,但是缺点也很明显,没有位图表达的色彩丰富。
    然而现在app风格越来越扁平, 拟物化已经成了过去,矢量图成了越来越多人的选择。但是,android和ios对于矢量图的支持还非常弱.

    android在最新的支持包中,已经加入了向下兼容的库:VectorDrawableCompat和AnimatedDrawableCompat,关于这两点的介绍网上很多,但是大多相同,但是有坑。今天我就围绕这个上代码,让未上车的猿们抓紧时间上车。


    首先,去哪找合适的矢量图:
    <a href="http://www.iconfont.cn/collections?spm=a313x.7781069.0.0.fEW4eG&personal=1">阿里巴巴UX矢量库 传送门</a>

    找到你需要的图标,并下载svg

    QQ图片20160521151928.png

    在android中打开vector assert

    ![4N`924]0H{31JI]I3IQ9CHH.png](https://img.haomeiwen.com/i2105494/21a2c1eb022cf76b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    点击Local SVG 选择路径,并命名drawable文件名字

    QQ图片20160521152031.png

    就在drawable目录生成了如下图

    QQ图片20160521152213.png

    ok, 一张可以任意缩放的图片有了。
    接着看怎么引用,
    先讲解一下, android L 以后矢量图是以vectorDrawable的形式来使用了, 但是这个库只支持L以后的,于是谷歌出了一个兼容包:
    VectorDrawableCompat,AnimatedVectorDrawableCompat

    As you may have seen on the Support Lib 23.2.0blog post, we now have compatible vector drawable implementations in the support libraries: VectorDrawableCompat and Animated VectorDrawableCompat.

    意思是说 在appcompat 23.2.0开始,提供了以上两种支持库一个用于兼容矢量图,但是这个支持库要使用的话,还得在app的gradle里面加个这样的配置:

    //在gradle2.0及以上:
    android {
      defaultConfig {
      vectorDrawables.useSupportLibrary = true
    }}
    //在gradle 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"
      }
    }
    

    ok , 配置完毕,下一步是怎么使用

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="10dp"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        >
    
       <android.support.v7.widget.AppCompatImageView
           android:layout_width="42dp"
           android:layout_height="42dp"
           app:srcCompat="@drawable/icon_shopping"/>
    
    
    </LinearLayout>
    
    
    QQ图片20160521161749.png

    ok , 可以使用,试着改变下图标大小,会发现,完全一样,没有一点模糊 。
    这里要说到,这种的局限性:
    1.只能用于AppCompatImageView或者AppCompatImageButton或其子类,而且必须在app:srcCompat标签中,额,那我要用在TextView,Button上怎么办?我试试:

    <android.support.v7.widget.AppCompatTextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="10dp"
           android:drawableLeft="@drawable/icon_shopping"
           android:text="我想要小图标"/>
    
     Caused by: android.content.res.Resources$NotFoundException: 
    File res/drawable/icon_shopping.xml from drawable resource ID #0x7f02004d
                                                                                  at android.content.res.Resources.loadDrawable(Resources.java:2101)
                                                                                  at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
                                                                                  at android.widget.TextView.<init>(TextView.java:806)
                                                                                  at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60)
                                                                                  at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56)
    

    嗯,除了一大堆错误,没有别的效果, 怎么办?

    You don’t have to use StateListDrawable. It also works with InsetDrawable, LayerDrawable, LevelListDrawable and RotateDrawable containers. The only rule is that the vector needs to be in a separate file.

    在android官方推文中找到这句话 , 意味着,我们要在普通控件上使用Vector,就必须依附于StateListDrawable,InsetDrawable,LayerDrawable,LevelListDrawable,RotateDrawable,所以我来试试?

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/icon_shopping"/>
    </selector>
    
     <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="10dp"
           android:drawableLeft="@drawable/shopping_res"
           android:text="我想要小图标"/>
    

    结果,相信有些哥们也尝试到这里了, 仍然是一大堆的错误。。。嗯,不是说包在那几个drawable里面就可以用了吗?忽悠人?这个帖子就此结束?
    不不不。

    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.

    我英文不太好, 应该是说,在23.2.0中放出了这个功能,但是后来发现了一些bug ,在23.3.0里面又移除了,后来在23.4.0中修复这些bug , 但是我们没有默认开启了,你需要通过一个标志来启用,呵呵哒。。这就是报错的原因了。。

    If you want re-enable this, just stick this at the top of your Activity:

    static {
      AppCompatDelegate.setCompatVectorFromSourcesEnabled(true);
    }
    

    嗯,这句话简单, 就是说,你要想再用上, 就在你的activity里面加上这句来启用vector ,
    结果怎样呢?

    QQ图片20160521164549.png

    ok ~问题解决。嗯,到了这一步,我们已经可以自由的使用矢量图标了呢,
    那怎么改变图标颜色呢?这个我要说声抱歉,我还没有想在xml里面设置图标背景的方法, 有人会说drawableTint,这个可以,但是只支持api23以上,嗯,所以:
    1.对于vector,我只想到了在xml里面改变fillColor来改变颜色,但这样就不好了,几个颜色就要几个图片,
    2.可以用代码在合适的位置设置:

     VectorDrawableCompat a = VectorDrawableCompat.create(getResources(), R.drawable.icon_shopping, getTheme());
            a.setTint(Color.RED); //设置单一的颜色
            a.setTintList(ColorStateList.valueOf(Color.RED));//设置状态性的,比如点击一个颜色,未点击一个颜色 
    
    DrawableCompat.setTint(a,Color.RED); //用这个v4提供的也可,这个适用于任意的drawable着色
    

    3.可以在AnimatedVectorDrawable中用动画来改变vector的颜色 ,
    嗯,第三个方案涉及的知识又多了起来, 这个可以再起一个博客详细来说,先略过。


    嗯,说好了爬坑,就不可能到这里就结束了。

    前面所说的这个矢量图只能用在AppcomatImageView,AppcompatImageButton,
    但实际上,用ImageView,ImageButton加上app:srcCompat也行, 为什么?因为你用了appcomat后,它会自动的把你的一部分控件转成AppCompatXxx的控件。


    总结一下,这个矢量图的缺点吧:

    1.麻烦, 需要下载->vector asset转换->用在非imageview中还要再写一个xml包裹起来才可用
    2.不能随心所欲的在xml布局中任意切换图标颜色 , 如果在vector的xml里面改fillcolor,则这个图标就不好复用了。我的意思则是一处创建,随意使用。
    3.支持库正在更新的过程中, 可能出现各种各样bug,也可能出现前面改动api实现而掉坑的情况。
    

    那怎么办?怎么办?
    前面介绍的 :

    <a href="http://www.iconfont.cn/collections?spm=a313x.7781069.0.0.fEW4eG&personal=1">阿里巴巴UX矢量库 传送门</a>

    对,就是它。后面要介绍的

    iconfont

    它的原理是,把你想要的矢量图标打包成一个ttf,在android中应用这个ttf,就可以随心所欲了,怎么个随心所欲?
    用TextView的setText设置图标, setTextSize设置大小, 用TextColor设置图标颜色 ,只要能显示String的控件,都可以用,这样说来如何 ?

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="10dp"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        >
    
       <android.support.v7.widget.AppCompatImageView
           android:layout_width="42dp"
           android:layout_height="42dp"
           app:srcCompat="@drawable/icon_shopping"/>
    
       <android.support.v7.widget.AppCompatTextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="10dp"
           android:drawableLeft="@drawable/shopping_res"
           android:text="我想要小图标"/>
    
       <com.example.liufan.demo1.IconfontView
           android:layout_width="wrap_content"
           android:layout_marginTop="10dp"
           android:textSize="60sp"
           android:textColor="#f00"
           android:text=""
           android:layout_height="wrap_content" />
    </LinearLayout>
    
    
    Paste_Image.png

    这个IconfontView,是继承自TextView,在初始化的时候加载了字体而已,
    & # xe725; 这个是上图图标的代码。
    嗯,这个并不算是什么高科技, 只是一个字体而已, 我就不长篇大论了, 下面贴出获取的流程吧,图从官网拿的:

    Paste_Image.png

    选中一堆需要的图标并加入购物车, 然后再这里点下载到本地,

    Paste_Image.png

    其中iconfont.ttf就是我们需要的字体了, 其他的那些在web上用的, 可以忽略。把iconfont.ttf复制到项目中assets中,然后,

    public class IconfontView extends TextView {
    
      
    
        public IconfontView(Context context) {
            super(context);
            initFont();
        }
    
        public IconfontView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initFont();
        }
    
        public IconfontView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initFont();
        }
    
        private void initFont() {
           final Typeface iconfont = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "iconfont/iconfont.ttf");
            setTypeface(iconfont );
        }
    }
    

    这里就是替换一下字体而已,还有就是这个iconfont什么的, 这个我由于写的是demo就写死的, 这里可以自定义一个属性,用来指定具体要用的字体 。

    ok , 现在打开解压目录的demo.html

    Paste_Image.png

    每个图标下的& #xe000就是这个图标的代码, 可以在IconfontView的text中设置了, 看下效果,

    
        <com.example.liufan.demo1.IconfontView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="&#xe60b;"
            android:textColor="#f00"
            android:textSize="200sp" />
    
        <com.example.liufan.demo1.IconfontView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="&#xe60b;"
            android:textColor="#f0f"
            android:textSize="200sp" />
    
    Paste_Image.png

    好了, 就是这些了, 基本全面, 如果帮忙您,希望您能帮我顶起来让更多人看到,
    如果说的有误,希望我能收到您的指正。

    相关文章

      网友评论

      • 14a913ac137c:我遇到这个坑,搞了差不多一天,真心累!看完您的文章,解决了问题,开阔了视野,真心赞!
      • 程序员联盟:不错啊
      • 大大大大峰哥:很有帮助
      • joychine:static {
        AppCompatDelegate.setCompatVectorFromSourcesEnabled(true);
        } 这个在 最新的 25.1.0 不存在了,已经改名为
        AppCompatDelegate.setCompatVectorFromResourcesEnabled() :grin:
      • f2d7dd94d72d:very nice!!!
      • 皮球二二:博主你知道如何更改VectorDrawable中某一个Path的颜色值吗?
        205蚁:@r17171709 请问改变某一个path的颜色实现了吗
      • 弦小杰:现在好像只能用app:srcCompat和setImageResources( )了
      • 无玄:写的不错,学习下
      • 攻城狮Song:希望能带上DEMO下载链接就最好了... :smiley:
        a帆仔:@攻城狮Song 还有,animatedvectorcompat这个支持库据我了解,在5.0以下只支持fillcolor,strokecolor两个动画,所以没法像这篇文章一样介绍了
        a帆仔:@攻城狮Song 随手写的一些例子,代码都贴上来了,所以没有放demo
      • dc9eb52dcd5e:每次发的文章都不错,学习了很多!已关注!
        a帆仔:@云木音 😉
      • yangjianan:给力!! 有个问题想请教, android:layout_width 跟 height 属性不生效了? 美工给的 是宽高dp, 请问有什么办法吗? :grin:
        a帆仔:@yangjianan 你试试吧,把宽高固定死,然后一点点加大字体尺寸,
        yangjianan:@a帆仔 比如说宽高现在是42dp,42dp, 那么textSize设置多少呢 :joy:
        a帆仔:@yangjianan 用矢量字体的话,就只能通过textsize来定大小了,宽高不能决定图标大小
      • 欧阳明日123:文章写的很不错~~!
      • Eric_Hu:给力
      • 谷青_vm:支持下
      • 二十三岁:学习 很棒
      • 囧_囧:棒棒哒

      本文标题:关于android中矢量图如何用,有坑,爬坑,如何替代的另一些看

      本文链接:https://www.haomeiwen.com/subject/xcqorttx.html