Search code examples
androidkotlintextviewandroid-drawablemarkwon

How to center a drawable image within a TextView?


I use the Markwon library to show markdown text with images. When the image is in the same line as the text, it is placed below the text. How to center the image?

Now:

enter image description here

Expect:

enter image description here

I have tried the following points, but nothing works:

  • TextView: android:drawablePadding="-20dp"
  • TextView: android:layout_gravity="center_vertical"
  • TextView: android:gravity="center_vertical"
// https://noties.io/Markwon/docs/v4/image/#custom-schemehandler
class DrawableImagesConfigure(private val context: Context) : ImagesPlugin.ImagesConfigure {

    override fun configureImages(plugin: ImagesPlugin) {
        plugin.addSchemeHandler(schemeHandler)
    }

    private val schemeHandler = object : SchemeHandler() {
        // will handle URLs like `drawable://ic_account?size=30`
        override fun handle(raw: String, uri: Uri): ImageItem {
            val rawSplitted = raw.split("drawable://", "?")
            val drawableName = rawSplitted[1]
            val queryMap =  parseQuery(rawSplitted.getOrNull(2))

            val drawableId = context.resources.getIdentifier(drawableName, "drawable", context.packageName)
            val drawable = AppCompatResources.getDrawable(context, drawableId)
                ?: throw Exception("The drawable with drawableId $drawableId does not exist")

            if (queryMap != null && queryMap["size"] != null) {
                val size = queryMap["size"]!!.toInt().toPx
                drawable.setBounds(0, 0, size, size)
            }

            return ImageItem.withResult(drawable)
        }

        override fun supportedSchemes(): Collection<String> {
            return setOf("drawable")
        }

        private fun parseQuery(rawQuery: String?): Map<String, String>? {
            return rawQuery?.split("&")
                ?.map { it.split("=") }
                ?.associate { (key, value) -> key to value }
        }
    }
}

<TextView
    android:id="@+id/markdown_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginHorizontal="@dimen/view_indent_horizontal"
    android:scrollbarThumbVertical="@android:color/transparent"
    android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
    android:textColor="?attr/colorOnBackground"
    android:textIsSelectable="true"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="48dp"
    android:height="48dp"
    android:viewportWidth="112.19"
    android:viewportHeight="112.19">
    <path
        android:fillColor="#D31F27"
        android:pathData="M112.19,56.1c0,30.98 -25.11,56.1 -56.1,56.1C25.11,112.19 0,87.08 0,56.1C0,25.12 25.11,0 56.1,0C87.08,0 112.19,25.12 112.19,56.1z" />
    <path
        android:fillColor="#FFFFFF"
        android:pathData="M80.49,52.14c-6.2,-1.85 -8.41,-2.87 -8.41,-4.92c0,-3.42 4.94,-4.7 5.5,-4.79c3.14,-0.47 7.07,1.17 8.34,4.99l8.44,-2.55c-2.65,-8.39 -10.49,-12.1 -18.1,-10.98c-7.79,1.15 -12.78,6.79 -12.78,13.33c0,8.8 8.24,11.33 14.43,13.18c6.51,1.94 8.4,2.64 8.4,5.02c0,2.02 -1.2,3.89 -4.37,4.74c-6.32,1.66 -14.59,-0.67 -16.89,-4.52c-1.35,-2.26 -2.73,-5.2 -4,-8.53c-3.77,-9.87 -8.93,-23.37 -23.76,-23.37c-7.73,0 -21.85,3.74 -21.85,24.87c0,8.74 7.48,19.61 21.58,19.61c11.83,0 13.89,-4.32 14.36,-5.09l-3.86,-7.55c-0.1,0.14 -3.69,4.94 -10.5,4.94c-11.11,0 -12.73,-11.78 -12.73,-11.91c0,-10.97 4.69,-16.24 13.01,-16.24c8.09,0 11.38,7.04 15.48,17.76c1.4,3.68 2.92,6.97 4.65,9.86c3.66,6.12 11.55,8.09 19.47,8.09c2.42,0 5.2,0.14 7.35,-0.43c7.09,-1.88 10.9,-6.18 10.9,-12.22C95.14,56.22 86.85,54.04 80.49,52.14z" />
</vector>

Solution

  • // https://github.com/noties/Markwon/blob/master/markwon-core/src/main/java/io/noties/markwon/image/ImageSpanFactory.java
    class AlignImagesPlugin : AbstractMarkwonPlugin() {
    
        override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
            builder.appendFactory(Image::class.java) { configuration, props ->
                AsyncDrawableSpan(
                    configuration.theme(),
                    AsyncDrawable(
                        ImageProps.DESTINATION.require(props),
                        configuration.asyncDrawableLoader(),
                        configuration.imageSizeResolver(),
                        ImageProps.IMAGE_SIZE[props]
                    ),
                    AsyncDrawableSpan.ALIGN_CENTER, // changed
                    ImageProps.REPLACEMENT_TEXT_IS_LINK[props, false]
                )
            }
        }
    
    }