Files
assistant-android/app/src/main/java/com/gh/common/util/TextViewExt.kt

135 lines
4.1 KiB
Kotlin

package com.gh.common.util
import android.content.Context
import android.graphics.Color
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.UnderlineSpan
import android.view.View
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
/**
* @author : liujiarui
* date : 2023/3/22
* description : 文本颜色事件控制
*/
//作用域进行限制
@DslMarker
@Target(AnnotationTarget.TYPE)
annotation class TextSpanDsl
interface DslSpannableStringBuilder {
//增加一段文字
fun addText(text: String, method: (@TextSpanDsl DslSpanBuilder.() -> Unit)? = null)
fun addText(@StringRes stringRes: Int, method: (@TextSpanDsl DslSpanBuilder.() -> Unit)? = null)
}
interface DslSpanBuilder {
//设置文字颜色文本
fun setColor(color: String)
//设置文字颜色int
fun setColor(color: ColorInt)
//设置文字颜色id
fun setColor(color: ColorResId)
//设置点击事件
fun onClick(useUnderLine: Boolean = false, onClick: (View) -> Unit)
}
//为 TextView 创建扩展函数,其参数为接口的扩展函数
fun TextView.buildSpannableString(init: @TextSpanDsl DslSpannableStringBuilder.() -> Unit) {
//具体实现类
val spanStringBuilderImpl = DslSpannableStringBuilderImpl(context)
spanStringBuilderImpl.init()
movementMethod = LinkMovementMethod.getInstance()
//通过实现类返回SpannableStringBuilder
text = spanStringBuilderImpl.build()
}
class DslSpannableStringBuilderImpl(val context: Context) : DslSpannableStringBuilder {
private val builder = SpannableStringBuilder()
//记录上次添加文字后最后的索引值
private var lastIndex: Int = 0
var isClickable = false
override fun addText(text: String, method: (@TextSpanDsl DslSpanBuilder.() -> Unit)?) {
val start = lastIndex
builder.append(text)
lastIndex += text.length
val spanBuilder = DslSpanBuilderImpl(context)
method?.let { spanBuilder.it() }
spanBuilder.apply {
onClickSpan?.let {
builder.setSpan(it, start, lastIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
isClickable = true
}
if (!useUnderLine) {
val noUnderlineSpan = NoUnderlineSpan()
builder.setSpan(noUnderlineSpan, start, lastIndex, Spanned.SPAN_MARK_MARK)
}
foregroundColorSpan?.let {
builder.setSpan(it, start, lastIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
override fun addText(stringRes: Int, method: (@TextSpanDsl DslSpanBuilder.() -> Unit)?) {
val text = context.getString(stringRes)
addText(text, method)
}
fun build(): SpannableStringBuilder {
return builder
}
}
class DslSpanBuilderImpl(val context: Context) : DslSpanBuilder {
var foregroundColorSpan: ForegroundColorSpan? = null
var onClickSpan: ClickableSpan? = null
var useUnderLine = true
override fun setColor(color: String) {
foregroundColorSpan = ForegroundColorSpan(Color.parseColor(color))
}
override fun setColor(color: ColorInt) {
foregroundColorSpan = ForegroundColorSpan(color.color)
}
override fun setColor(color: ColorResId) {
val c = ContextCompat.getColor(context, color.colorResId)
foregroundColorSpan = ForegroundColorSpan(c)
}
override fun onClick(useUnderLine: Boolean, onClick: (View) -> Unit) {
onClickSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
onClick(widget)
}
}
this.useUnderLine = useUnderLine
}
}
@JvmInline
value class ColorInt(val color: Int)
@JvmInline
value class ColorResId(val colorResId: Int)
class NoUnderlineSpan : UnderlineSpan() {
override fun updateDrawState(ds: TextPaint) {
ds.color = ds.linkColor
ds.isUnderlineText = false
}
}