带有路径的自定义跨度复制路径
Custom Span with path duplicates the path
我想给TextView Spans画一条曲线下划线,所以我自定义了span和textview如下:
class UnderscoreSpan(context: Context) : ReplacementSpan() {
private val underscoreHeight = context.resources.getDimension(R.dimen.underscoreHeight)
private val vectorPath = Path()
override fun getSize(
paint: Paint,
text: CharSequence,
start: Int,
end: Int,
fm: FontMetricsInt?
): Int {
return measureText(paint, text, start, end).roundToInt()
}
private fun measureText(paint: Paint, text: CharSequence, start: Int, end: Int): Float {
return 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
) {
val w = measureText(paint, text, start, end)
val h = bottom.toFloat() - top.toFloat()
paint.color = Color.RED
paint.strokeWidth = underscoreHeight
paint.style = Paint.Style.STROKE
vectorPath.moveTo(x, bottom.toFloat() - underscoreHeight)
vectorPath.cubicTo(
x + w / 2,
bottom - underscoreHeight - h / 10,
x + w - w / 5,
bottom - underscoreHeight + h / 20,
x + w,
bottom - underscoreHeight,
)
canvas.save()
canvas.drawPath(vectorPath, paint)
paint.color = Color.BLACK
paint.style = Paint.Style.FILL
paint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
canvas.drawText(text, start, end, x, y.toFloat(), paint)
canvas.restore()
}
}
class UnderscoreSpanTextView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
fun setSpannableText(text: String) {
val start = text.findAnyOf(listOf("<b>"))?.first ?: 0
val temp = text.replace("<b>", "")
val end = temp.findAnyOf(listOf("</b>"))?.first ?: 0
val finalText = temp.replace("</b>", "")
val spannable = SpannableString(finalText)
spannable.setSpan(
UnderscoreSpan(context),
start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
super.setText(spannable)
}
}
但是,路径被绘制了两次,并有几个像素的偏移。如果我不使用路径(例如只使用 drawRect),那也没关系。然而,对于路径,它总是双重的,即使我关闭路径并且不使用笔划。我做错了什么?
在第二次 onDraw 调用中,我未能重置路径变量,因此重绘了它。所以它所需要的只是在 draw().
开始时调用 path.reset()
我想给TextView Spans画一条曲线下划线,所以我自定义了span和textview如下:
class UnderscoreSpan(context: Context) : ReplacementSpan() {
private val underscoreHeight = context.resources.getDimension(R.dimen.underscoreHeight)
private val vectorPath = Path()
override fun getSize(
paint: Paint,
text: CharSequence,
start: Int,
end: Int,
fm: FontMetricsInt?
): Int {
return measureText(paint, text, start, end).roundToInt()
}
private fun measureText(paint: Paint, text: CharSequence, start: Int, end: Int): Float {
return 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
) {
val w = measureText(paint, text, start, end)
val h = bottom.toFloat() - top.toFloat()
paint.color = Color.RED
paint.strokeWidth = underscoreHeight
paint.style = Paint.Style.STROKE
vectorPath.moveTo(x, bottom.toFloat() - underscoreHeight)
vectorPath.cubicTo(
x + w / 2,
bottom - underscoreHeight - h / 10,
x + w - w / 5,
bottom - underscoreHeight + h / 20,
x + w,
bottom - underscoreHeight,
)
canvas.save()
canvas.drawPath(vectorPath, paint)
paint.color = Color.BLACK
paint.style = Paint.Style.FILL
paint.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
canvas.drawText(text, start, end, x, y.toFloat(), paint)
canvas.restore()
}
}
class UnderscoreSpanTextView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
fun setSpannableText(text: String) {
val start = text.findAnyOf(listOf("<b>"))?.first ?: 0
val temp = text.replace("<b>", "")
val end = temp.findAnyOf(listOf("</b>"))?.first ?: 0
val finalText = temp.replace("</b>", "")
val spannable = SpannableString(finalText)
spannable.setSpan(
UnderscoreSpan(context),
start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
super.setText(spannable)
}
}
但是,路径被绘制了两次,并有几个像素的偏移。如果我不使用路径(例如只使用 drawRect),那也没关系。然而,对于路径,它总是双重的,即使我关闭路径并且不使用笔划。我做错了什么?
在第二次 onDraw 调用中,我未能重置路径变量,因此重绘了它。所以它所需要的只是在 draw().
开始时调用 path.reset()