1

I'm trying to show an arrow unicode symbol within a TextView but for some reason, the charcter doesn't match the size of the text desite using the Html.fromHtml code. Is there something that can be done to fix this?

enter image description here

Activity layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/myTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:textAppearanceLarge"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Activity class

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mTV = findViewById<TextView>(R.id.myTV)

        mTV.text = Html.fromHtml(getString(R.string.app_name) + " \u2192 " + getString(R.string.app_name), Html.FROM_HTML_MODE_COMPACT)
    }
}
wbk727
  • 8,017
  • 12
  • 61
  • 125
  • [Why is TextView showing the unicode right arrow (\u2192) at the bottom line?](https://stackoverflow.com/q/49315570/3290339) – Onik Nov 30 '20 at 22:01
  • @Onik This doesn't work doesn't when trying to do the same thing on multiple lines – wbk727 Nov 30 '20 at 22:11

1 Answers1

0

Roboto (the system font) doesn't have arrow glyphs, so what you're seeing there is some kind of uh-oh fallback, which you don't seem to be able to style (including through styling tags in your HTML string). So what you can do instead, is stick an <img> tag in there, using an ImageGetter to provide it with a drawable

class MainActivity : AppCompatActivity() {
    @RequiresApi(Build.VERSION_CODES.N)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mTV = findViewById<TextView>(R.id.myTV)
        val appName = getString(R.string.app_name)
        val template = "$appName <img src=\"arrow\"/> $appName"
        mTV.text = Html.fromHtml(template, Html.FROM_HTML_MODE_COMPACT, imageGetter, null)
    }

    private val imageGetter = Html.ImageGetter { name ->
        val resId = when (name) {
            "arrow" -> R.drawable.ic_baseline_arrow_right_alt_24
            else -> throw IllegalArgumentException("what the heck is $name")
        }

        ResourcesCompat.getDrawable(resources, resId, theme)?.apply {
            // size the arrow here - we need to scale it with the font size,
            // so set its width and height in the XML to sp units
            setBounds(0, 0, intrinsicWidth, intrinsicHeight)
        }
    }
}

So this is basically using taking the value of the src attribute in the img tag and passing it to imageGetter, which is just doing a simple mapping to drawable resource IDs.

Then it loads and sizes the drawable - which needs to be scaled to the equivalent sp value, so it scales with the text size. It's easiest to just set that in the drawable, and you can tweak the values to get it sized nicely relatively to the text:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="28sp"
    android:height="28sp"
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="?attr/colorOnSurface">
  <path
      android:fillColor="@android:color/white"
      android:pathData="M16.01,11H4v2h12.01v3L20,12l-3.99,-4z"/>
</vector>

This is just the baseline_arrow_right drawable you can get from the Vector Assets thing in Resource Manager. Note the width and height are in sp not dp, otherwise it wouldn't scale with the system font size.

Also you'll need to make sure it's themed properly, I set the colour to colorOnSurface but you'll have work that out for yourself! There's ?android:attr/textColor but you might have to set the image as enabled for it to look right

what the fixed version looks like

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • To clarify, what would happen if `android:fillColor="@android:color/white"` wasn't there? – wbk727 Dec 02 '20 at 16:58
  • As far as I know, it just defines the path as having a fill, so it's a solid shape - there's a ``strokeColor`` one too, if you have neither it probably doesn't display, because there's nothing being drawn with the path. But that's just how the XML looks when you import a vector asset, I just changed the tint and dimensions – cactustictacs Dec 02 '20 at 17:22