Android 自定义 svg 颜色

作者: stormKid | 来源:发表于2018-10-15 15:07 被阅读38次

    1、XML 设定颜色

      <vector android:height="24dp" android:viewportHeight="1024"
        android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
        <path android:fillColor="#FFF" android:pathData="M395.22,513.6l323.14,-312.37c19.05,-18.42 19.05,-48.27 0,-66.66 -19.05,-18.42 -49.91,-18.42 -68.96,0L291.75,480.29c-19.05,18.42 -19.05,48.27 0,66.66l357.63,345.69c9.53,9.21 22.01,13.8 34.5,13.8 12.49,0 24.97,-4.59 34.47,-13.83 19.05,-18.42 19.05,-48.24 0,-66.66L395.22,513.6z"/>
      </vector>
    

    xml设定颜色很简单,fillColor 这个attr即可设定。

    2、kotlin代码动态设定颜色

    先构造一个适用的对象

    /**
     * svg 图片需要构建的对象
     */
    data class InitImgRes(
            @DrawableRes val imgRes: Int,
            @ColorRes val colorRes: Int,
            val imageView: ImageView,
            val context: Context
    )
    

    一般很多博客是这样写的:

       /**
         * 给imageView 的svg初始化颜色
         */
        fun initSvgColor(initImgRes: InitImgRes){
            // 获取该image的资源
            val res  = initImgRes.context.resources
            // 获取该image的主题对象
            val theme = initImgRes.context.theme
            //创造vectorDrawable工具对象,影响vectorView绘制
            val vectorDrawableCompat = VectorDrawableCompat.create(res,initImgRes.imgRes,theme) ?: return
            // 使用Tint上色
            if (Build.VERSION.SDK_INT>22)
            vectorDrawableCompat.setTint(res.getColor(initImgRes.colorRes,theme))
            else vectorDrawableCompat.setTint(res.getColor(initImgRes.colorRes))
            initImgRes.imageView.setImageDrawable(vectorDrawableCompat)
        }
    
    

    VectorDrawableCompat create源码如下:

       @Nullable
        public static VectorDrawableCompat create(@NonNull Resources res, @DrawableRes int resId, @Nullable Theme theme) {
            if (VERSION.SDK_INT >= 24) {
                VectorDrawableCompat drawable = new VectorDrawableCompat();
                drawable.mDelegateDrawable = ResourcesCompat.getDrawable(res, resId, theme);
                drawable.mCachedConstantStateDelegate = new VectorDrawableCompat.VectorDrawableDelegateState(drawable.mDelegateDrawable.getConstantState());
                return drawable;
            } else {
                try {
                    XmlPullParser parser = res.getXml(resId);
                    AttributeSet attrs = Xml.asAttributeSet(parser);
    
                    int type;
                    while((type = parser.next()) != 2 && type != 1) {
                        ;
                    }
    
                    if (type != 2) {
                        throw new XmlPullParserException("No start tag found");
                    }
    
                    return createFromXmlInner(res, parser, attrs, theme);
                } catch (XmlPullParserException var6) {
                    Log.e("VectorDrawableCompat", "parser error", var6);
                } catch (IOException var7) {
                    Log.e("VectorDrawableCompat", "parser error", var7);
                }
    
                return null;
            }
        }
    
    调用影响state方法.png

    根据源码,我们不难看出在24之前,通过drawable的xml解析,来上色,这样效率非常低,再通过24之后的版本,自建了一个drawable对象,在此对象中运行影响VectorView的state这样造成的后果是,VectorView的state永远赋值,当前xml下的svg永远上色为最后一个颜色。故抛弃此类写法


    正确代码写法:

        /**
         * 给imageView 的svg初始化颜色
         */
        fun initSvgColor(initImgRes: InitImgRes){
            //利用ContextCompat工具类获取drawable图片资源
            val drawable = ContextCompat.getDrawable(initImgRes.context, initImgRes.imgRes)?:return
            //简单的使用tint改变drawable颜色
            val drawableResult = tintDrawable(drawable,ContextCompat.getColor(initImgRes.context, initImgRes.colorRes))
            initImgRes.imageView.setImageDrawable(drawableResult)
        }
    
        /**
         * 给drawable上色 
         */
         private fun  tintDrawable( drawable:Drawable, colors:Int): Drawable {
            val wrap = DrawableCompat.wrap(drawable).mutate()
            DrawableCompat.setTint(wrap,colors)
            return wrap
        }
    

    再查看源码:

    mutate方法源码解释.png

    源码注释告诉了我们:此获取的drawable不与其他drawable 共享,简而言之,就是构建单独的内存模块来存储此drawable达到相互不影响的状态。

    此种写法代码量减少的很明显,很能理解,先直接获取svg 的drawable 对象,然后通过预设资源,获取颜色进而给当前对象上色即可,不需要影响vectorView绘制。推荐使用。

    相关文章

      网友评论

        本文标题:Android 自定义 svg 颜色

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