Use OutlineSpan approach from CarlosEsco/Neko to avoid infinite redraws

Based on work by @arsonistAnt: 1876f850f6
This commit is contained in:
arkon 2020-01-09 22:13:25 -05:00
parent f715478070
commit 745f8d32b5
2 changed files with 75 additions and 24 deletions

View file

@ -2,15 +2,14 @@ package eu.kanade.tachiyomi.ui.reader
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint
import androidx.appcompat.widget.AppCompatTextView
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
import android.text.style.ScaleXSpan import android.text.style.ScaleXSpan
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView
import eu.kanade.tachiyomi.widget.OutlineSpan
/** /**
* Page indicator found at the bottom of the reader * Page indicator found at the bottom of the reader
@ -20,19 +19,8 @@ class PageIndicatorTextView(
attrs: AttributeSet? = null attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) { ) : AppCompatTextView(context, attrs) {
private val fillColor = Color.rgb(235, 235, 235) init {
private val strokeColor = Color.rgb(45, 45, 45) setTextColor(fillColor)
override fun onDraw(canvas: Canvas) {
textColorField.set(this, strokeColor)
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
super.onDraw(canvas)
textColorField.set(this, fillColor)
paint.strokeWidth = 0f
paint.style = Paint.Style.FILL
super.onDraw(canvas)
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@ -42,20 +30,26 @@ class PageIndicatorTextView(
val currText = " $text " val currText = " $text "
// Also add a bit of spacing between each character, as the stroke overlaps them // Also add a bit of spacing between each character, as the stroke overlaps them
val finalText = SpannableString(currText.asIterable().joinToString("\u00A0")) val finalText = SpannableString(currText.asIterable().joinToString("\u00A0")).apply {
// Apply text outline
setSpan(spanOutline, 1, length-1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
for (i in 1..finalText.lastIndex step 2) { for (i in 1..lastIndex step 2) {
finalText.setSpan(ScaleXSpan(0.1f), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) setSpan(ScaleXSpan(0.2f), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
} }
super.setText(finalText, TextView.BufferType.SPANNABLE) super.setText(finalText, TextView.BufferType.SPANNABLE)
} }
private companion object { private companion object {
// We need to use reflection to set the text color instead of using [setTextColor], private val fillColor = Color.rgb(235, 235, 235)
// otherwise the view is invalidated inside [onDraw] and there's an infinite loop private val strokeColor = Color.rgb(45, 45, 45)
val textColorField = TextView::class.java.getDeclaredField("mCurTextColor").apply {
isAccessible = true // A span object with text outlining properties
}!! val spanOutline = OutlineSpan(
strokeColor = strokeColor,
strokeWidth = 4f
)
} }
} }

View file

@ -0,0 +1,57 @@
package eu.kanade.tachiyomi.widget
import android.graphics.Canvas
import android.graphics.Paint
import android.text.style.ReplacementSpan
import androidx.annotation.ColorInt
import androidx.annotation.Dimension
/**
* Source: https://github.com/santaevpavel
*
* A class that draws the outlines of a text when given a stroke color and stroke width.
*/
class OutlineSpan(
@ColorInt private val strokeColor: Int,
@Dimension private val strokeWidth: Float
) : ReplacementSpan() {
override fun getSize(
paint: Paint,
text: CharSequence,
start: Int,
end: Int,
fm: Paint.FontMetricsInt?
): Int {
return paint.measureText(text.toString().substring(start until end)).toInt()
}
override fun draw(
canvas: Canvas,
text: CharSequence,
start: Int,
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
val originTextColor = paint.color
paint.apply {
color = strokeColor
style = Paint.Style.STROKE
this.strokeWidth = this@OutlineSpan.strokeWidth
}
canvas.drawText(text, start, end, x, y.toFloat(), paint)
paint.apply {
color = originTextColor
style = Paint.Style.FILL
}
canvas.drawText(text, start, end, x, y.toFloat(), paint)
}
}