Background
I am trying to use a simple SpannableString on a TextView based on the UnderDotSpan class that I found ( here ).
The original UnderDotSpan simply places a dot of a certain size and color below the text itself (without overlapping). I try to use it in normal mode first, and then use a personalized drawable method instead of a dot.
Problem
Unlike normal range usage, this one just doesn't show anything. Even the text.
Here's how to do it for the normal range:
val text = "1" val timeSpannable = SpannableString(text) timeSpannable.setSpan(ForegroundColorSpan(0xff00ff00.toInt()), 0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) textView.setText(timeSpannable);
it will display green "1" in the TextView.
But when I try the following spannable, it (all TextView text: text and dot) doesn't display at all:
val text = "1" val spannable = SpannableString(text) spannable.setSpan(UnderDotSpan(this@MainActivity, 0xFF039BE5.toInt(), textView.currentTextColor), 0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) textView.setText(spannable, TextView.BufferType.SPANNABLE) // this also didn't work: textView.setText(spannable)
It is strange that in one project that I use, it works fine inside RecyclerView, and in another it doesnβt.
Here's the UnderDotSpan code:
class UnderDotSpan(private val mDotSize: Float, private val mDotColor: Int, private val mTextColor: Int) : ReplacementSpan() { companion object { @JvmStatic private val DEFAULT_DOT_SIZE_IN_DP = 4 } constructor(context: Context, dotColor: Int, textColor: Int) : this(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_DOT_SIZE_IN_DP.toFloat(), context.resources.displayMetrics), dotColor, textColor) {} override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?) = Math.round(paint.measureText(text, start, end)) override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { if (TextUtils.isEmpty(text)) { return } val textSize = paint.measureText(text, start, end) paint.color = mDotColor canvas.drawCircle(x + textSize / 2, bottom + mDotSize, mDotSize / 2, paint) paint.color = mTextColor canvas.drawText(text, start, end, x, y.toFloat(), paint) } }
Note that TextView does not have any special properties, but I will show it anyway:
<android.support.constraint.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="com.example.user.myapplication.MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> </android.support.constraint.ConstraintLayout>
What i tried
I tried spreading from other span classes, and also tried setting text in TextView in other ways.
I also tried other span classes that I created, based on the UnderDotSpan class. Example:
class UnderDrawableSpan(val drawable: Drawable, val drawableWidth: Int = drawable.intrinsicWidth, val drawableHeight: Int = drawable.intrinsicHeight, val margin: Int = 0) : ReplacementSpan() { override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int = Math.round(paint.measureText(text, start, end)) override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { if (TextUtils.isEmpty(text)) return val textSize = paint.measureText(text, start, end) canvas.drawText(text, start, end, x, y.toFloat(), paint) canvas.save() canvas.translate(x + textSize / 2f - drawableWidth / 2f, y.toFloat() + margin) if (drawableWidth != 0 && drawableHeight != 0) drawable.setBounds(0, 0, drawableWidth, drawableHeight) drawable.draw(canvas) canvas.restore() } }
During debugging, I found that the draw function is not even called, and getSize is called (and returns a value> 0).
Question
Why can't a range be displayed in a TextView?
What happened to the way I used it?
How can I fix it and use this range?
How could this work in other, more complex cases?