Is it possible to create a VectorDrawable from File System (*.xml File)

后端 未结 3 994
你的背包
你的背包 2021-02-08 12:07

I am trying to use VectorDrawables in my Android App.
I want to load an xml File from the File System and get an Instance of android.graphics.Drawable to displa

3条回答
  •  隐瞒了意图╮
    2021-02-08 12:41

    Yes, it is possible but sadly according to what someone shown me, it has multiple disadvantages:

    1. Requires reflection, so might not work some day
    2. The reflection is on private API, which is not recommended
    3. Works only on compiled VectorDrawable XML files.

    That being said, maybe you could create your own XmlPullParser by looking at the code of other libraries, such as here (or my fork of it, here). The interesting class name there is "BinaryXmlParser", which I think might help. I tried using other methods, but it caused an exception of java.lang.ClassCastException: android.util.XmlPullAttributes cannot be cast to android.content.res.XmlBlock$Parser , so maybe it wants to use only the reflected XmlBlock class, which means even if you do implement it, I think there is a good chance it won't work.

    Here's the code (based on here) :

    object VectorDrawableParser {
        /**
         * Create a vector drawable from a binary XML byte array.
         *
         * @param context Any context.
         * @param binXml  Byte array containing the binary XML.
         * @return The vector drawable or null it couldn't be created.
         */
        @SuppressLint("PrivateApi", "DiscouragedPrivateApi")
        fun getVectorDrawable(context: Context, binXml: ByteArray): Drawable? {
            try {
                // Get the binary XML parser (XmlBlock.Parser) and use it to create the drawable
                // This is the equivalent of what AssetManager#getXml() does
                val xmlBlock = Class.forName("android.content.res.XmlBlock")
                val xmlBlockConstr = xmlBlock.getConstructor(ByteArray::class.java)
                val xmlParserNew = xmlBlock.getDeclaredMethod("newParser")
                xmlBlockConstr.isAccessible = true
                xmlParserNew.isAccessible = true
                val parser = xmlParserNew.invoke(xmlBlockConstr.newInstance(binXml)) as XmlPullParser
                return if (Build.VERSION.SDK_INT >= 24) {
                    Drawable.createFromXml(context.resources, parser)
                } else {
                    // Before API 24, vector drawables aren't rendered correctly without compat lib
                    val attrs = Xml.asAttributeSet(parser)
                    var type = parser.next()
                    while (type != XmlPullParser.START_TAG) {
                        type = parser.next()
                    }
                    VectorDrawableCompat.createFromXmlInner(context.resources, parser, attrs, null)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return null
        }
    }
    

    And how to use:

    val filePath = "/storage/emulated/0/abc_vector_test.xml"
    val readBytes = FileInputStream(File(filePath)).readBytes()
    val vectorDrawable = VectorDrawableParser.getVectorDrawable(this, readBytes)
    Log.d("AppLog", "got it?${vectorDrawable != null}")
    

提交回复
热议问题