微信图片_20250212171111.png
在 Android 开发中,Span
是一种用于对 Spannable
文本进行样式设置和交互处理的机制。Spannable
是 CharSequence
的一个子接口,它允许你在文本的特定区域应用各种样式和行为,而不是对整个文本应用相同的属性。以下是关于 Android Span
的具体功能实现
Span说明:
- 1、BackgroundColorSpan 背景色
- 2、ClickableSpan 文本可点击,有点击事件
- 3、ForegroundColorSpan 文本颜色(前景色)
- 4、MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
- 5、MetricAffectingSpan 父类,一般不用
- 6、RasterizerSpan 光栅效果
- 7、StrikethroughSpan 删除线(中划线)
- 8、SuggestionSpan 相当于占位符
- 9、UnderlineSpan 下划线
- 10、AbsoluteSizeSpan 绝对大小(文本字体)
- 11、DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
- 12、ImageSpan 图片
- 13、RelativeSizeSpan 相对大小(文本字体)
- 14、ReplacementSpan 父类,一般不用
- 15、ScaleXSpan 基于x轴缩放
- 16、StyleSpan 字体样式:粗体、斜体等
- 17、SubscriptSpan 下标(数学公式会用到)
- 18、SuperscriptSpan 上标(数学公式会用到)
- 19、TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
- 20、TypefaceSpan 文本字体
- 21、URLSpan 文本超链接
1:工具类
package com.wkq.ui.util.span
/**
*
*@Author: wkq
*
*@Time: 2025/2/12 14:23
*
*@Desc:
*/
import android.content.Context
import android.graphics.BlurMaskFilter
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.style.AbsoluteSizeSpan
import android.text.style.BackgroundColorSpan
import android.text.style.ClickableSpan
import android.text.style.DynamicDrawableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.text.style.MaskFilterSpan
import android.text.style.RelativeSizeSpan
import android.text.style.ScaleXSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.text.style.SubscriptSpan
import android.text.style.SuperscriptSpan
import android.text.style.TextAppearanceSpan
import android.text.style.TypefaceSpan
import android.text.style.URLSpan
import android.text.style.UnderlineSpan
import android.widget.TextView
import androidx.annotation.RequiresApi
import com.wkq.ui.view.KtLinearGradientFontSpan
/**
* 用于处理 Android 中 SpannableString 的各种样式设置的工具类。
* 提供了丰富的方法来对文本进行多样化的样式定制,
* 最后还能将处理好的 SpannableString 追加到 TextView 中。
*/
class SpanUtils private constructor(private val context: Context) {
companion object {
@Volatile
private var instance: SpanUtils? = null
/**
* 获取 SpanUtils 的单例实例。
*
* @param context 应用程序上下文,用于访问资源等操作。
* @return SpanUtils 的单例实例。
*/
fun getInstance(context: Context): SpanUtils {
return instance ?: synchronized(this) {
instance ?: SpanUtils(context).also { instance = it }
}
}
}
/**
* 处理可能为 null 的文本,若文本为 null 则返回空字符串。
*
* @param text 待处理的文本,可能为 null。
* @return 处理后的非空文本,若原文本为 null 则返回 ""。
*/
private fun handleNullText(text: String?): String {
return text ?: ""
}
fun setTextTypeface(
startText: String?,
spanText: String?,
endText: String?,
startColor: Int = Color.GREEN,
endColor: Int = Color.GREEN,
isLeftToRight:Boolean=true
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
val span = KtLinearGradientFontSpan(startColor, endColor, isLeftToRight)
spannable.setSpan(
span, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的背景色。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param color 背景色,默认为绿色(Color.GREEN)。
* @return 应用了背景色样式的 SpannableString。
*/
fun setBackgroundColorSpan(
startText: String?,
spanText: String?,
endText: String?,
color: Int = Color.GREEN
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
BackgroundColorSpan(color), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 可点击及点击事件。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param clickListener 点击 spanText 时触发的回调函数。
* @return 应用了可点击样式的 SpannableString。
*/
fun setClickableSpan(
startText: String?,
spanText: String?,
endText: String?,
clickListener: (content:String) -> Unit
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: android.view.View) {
clickListener(handleNullText(spanText))
}
}
spannable.setSpan(clickableSpan, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 设置 spanText 的文本颜色(前景色)。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param color 前景色,默认为蓝色(Color.BLUE)。
* @return 应用了前景色样式的 SpannableString。
*/
fun setForegroundColorSpan(
startText: String?,
spanText: String?,
endText: String?,
color: Int = Color.BLUE
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
ForegroundColorSpan(color), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的修饰效果,如模糊、浮雕。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @return 应用了模糊和浮雕修饰效果的 SpannableString。
*/
fun setMaskFilterSpan(
startText: String?,
spanText: String?,
endText: String?
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
// 模糊(BlurMaskFilter)
val blurMaskFilterSpan = MaskFilterSpan(BlurMaskFilter(3f, BlurMaskFilter.Blur.OUTER))
spannable.setSpan(
blurMaskFilterSpan, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
// 浮雕(EmbossMaskFilter)
// val embossMaskFilterSpan =
// MaskFilterSpan(EmbossMaskFilter(floatArrayOf(1f, 1f, 1f), 0.2f, 28f, 5f))
// spannable.setSpan(
// embossMaskFilterSpan, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
// )
return spannable
}
/**
* 设置 spanText 的删除线(中划线)。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @return 应用了删除线样式的 SpannableString。
*/
fun setStrikethroughSpan(
startText: String?,
spanText: String?,
endText: String?
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
StrikethroughSpan(), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的下划线。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @return 应用了下划线样式的 SpannableString。
*/
fun setUnderlineSpan(
startText: String?,
spanText: String?,
endText: String?
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(UnderlineSpan(), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 设置 spanText 的绝对大小(文本字体)。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param size 字体的绝对大小。
* @param dip 若为 true,表示大小以 dip 为单位;若为 false,表示大小以像素为单位,默认为 true。
* @return 应用了绝对大小样式的 SpannableString。
*/
fun setAbsoluteSizeSpan(
startText: String?,
spanText: String?,
endText: String?,
size: Int,
dip: Boolean = true
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
AbsoluteSizeSpan(size, dip), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 中的图片,基于文本基线或底部对齐。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param drawableResId 图片资源的 ID。
* @param width 图片的宽度。
* @param height 图片的高度。
* @return 应用了图片样式(基线和底部对齐)的 SpannableString。
*/
fun setDynamicDrawableSpan(
startText: String?,
spanText: String?,
endText: String?,
drawableResId: Int,
width: Int,
height: Int
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
val drawableSpanBaseline =
object : DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
override fun getDrawable(): Drawable {
val d = context.resources.getDrawable(drawableResId)
d.setBounds(0, 0, width, height)
return d
}
}
spannable.setSpan(
drawableSpanBaseline, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
val drawableSpanBottom = object : DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BOTTOM) {
override fun getDrawable(): Drawable {
val d = context.resources.getDrawable(drawableResId)
d.setBounds(0, 0, width, height)
return d
}
}
spannable.setSpan(
drawableSpanBottom, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 中的图片。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param drawableResId 图片资源的 ID。
* @param width 图片的宽度。
* @param height 图片的高度。
* @return 应用了图片样式的 SpannableString。
*/
fun setImageSpan(
startText: String?,
spanText: String?,
endText: String?,
drawableResId: Int,
width: Int,
height: Int
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
val d = context.resources.getDrawable(drawableResId)
d.setBounds(0, 0, width, height)
spannable.setSpan(ImageSpan(d), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 设置 spanText 的相对大小(文本字体)。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param proportion 字体的相对大小比例。
* @return 应用了相对大小样式的 SpannableString。
*/
fun setRelativeSizeSpan(
startText: String?,
spanText: String?,
endText: String?,
proportion: Float
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
RelativeSizeSpan(proportion), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 基于 x 轴缩放 spanText。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param proportion x 轴的缩放比例。
* @return 应用了 x 轴缩放样式的 SpannableString。
*/
fun setScaleXSpan(
startText: String?,
spanText: String?,
endText: String?,
proportion: Float
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
ScaleXSpan(proportion), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的字体样式:粗体、斜体等。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param style 字体样式,默认为粗斜体(Typeface.BOLD_ITALIC)。
* @return 应用了字体样式的 SpannableString。
*/
fun setStyleSpan(
startText: String?,
spanText: String?,
endText: String?,
style: Int = Typeface.BOLD_ITALIC
): SpannableString {
val combinedText =
handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
StyleSpan(style), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的下标。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @return 应用了下标样式的 SpannableString。
*/
fun setSubscriptSpan(
startText: String?,
spanText: String?,
endText: String?
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(SubscriptSpan(), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 设置 spanText 的上标。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @return 应用了上标样式的 SpannableString。
*/
fun setSuperscriptSpan(
startText: String?,
spanText: String?,
endText: String?
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(SuperscriptSpan(), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 设置 spanText 的外貌(包括字体、大小、样式和颜色)。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param appearanceStyle 文本外貌的样式资源 ID,默认为 android.R.style.TextAppearance_Medium。
* @return 应用了文本外貌样式的 SpannableString。
*/
fun setTextAppearanceSpan(
startText: String?,
spanText: String?,
endText: String?,
appearanceStyle: Int = android.R.style.TextAppearance_Medium
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
TextAppearanceSpan(context, appearanceStyle),
startIndex,
endIndex,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的字体。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param typeface 字体名称,默认为 "monospace"。
* @return 应用了指定字体样式的 SpannableString。
*/
@RequiresApi(Build.VERSION_CODES.P)
fun setTypefaceSpan(
startText: String?,
spanText: String?,
endText: String?,
typeface: Typeface
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
TypefaceSpan(typeface),
startIndex,
endIndex,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
fun setTypefaceSpan(
startText: String?,
spanText: String?,
endText: String?,
typeface: String = "monospace"
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(
TypefaceSpan(typeface),
startIndex,
endIndex,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
return spannable
}
/**
* 设置 spanText 的超链接。
*
* @param startText 起始文本,若为 null 会被处理为空字符串。
* @param spanText 要设置样式的中间文本,若为 null 会被处理为空字符串。
* @param endText 结束文本,若为 null 会被处理为空字符串。
* @param url 超链接的 URL 地址。
* @return 应用了超链接样式的 SpannableString。
*/
fun setURLSpan(
startText: String?,
spanText: String?,
endText: String?,
url: String
): SpannableString {
val combinedText = handleNullText(startText) + handleNullText(spanText) + handleNullText(endText)
val startIndex = handleNullText(startText).length
val endIndex = startIndex + handleNullText(spanText).length
val spannable = SpannableString(combinedText)
spannable.setSpan(URLSpan(url), startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* 将 SpannableString 追加到 TextView 并设置可点击(针对 URLSpan 等)。
*
* @param textView 要追加文本的 TextView。
* @param spannable 要追加的 SpannableString。
*/
fun appendSpannableToTextView(textView: TextView, spannable: SpannableString) {
val builder = SpannableStringBuilder(textView.text)
builder.append("\n")
builder.append(spannable)
textView.text = builder
textView.movementMethod = android.text.method.LinkMovementMethod.getInstance()
}
}
2.调用
package com.wkq.tools.ui
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import com.wkq.tools.R
import com.wkq.tools.databinding.ActivityUiSpanBinding
import com.wkq.tools.databinding.ActivityUiTextviewBinding
import com.wkq.ui.util.WebViewUtil
import com.wkq.ui.util.span.CustomClickableSpan
import com.wkq.ui.util.span.SpanBuilder
import com.wkq.ui.util.span.SpanUtils
import com.wkq.ui.view.KtLinearGradientFontSpan
/**
*
*@Author: wkq
*
*@Time: 2025/2/11 15:10
*
*@Desc:
*
* * 1、BackgroundColorSpan 背景色
* * 2、ClickableSpan 文本可点击,有点击事件
* * 3、ForegroundColorSpan 文本颜色(前景色)
* * 4、MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
* * 5、MetricAffectingSpan 父类,一般不用
* * 6、RasterizerSpan 光栅效果
* * 7、StrikethroughSpan 删除线(中划线)
* * 8、SuggestionSpan 相当于占位符
* * 9、UnderlineSpan 下划线
* * 10、AbsoluteSizeSpan 绝对大小(文本字体)
* * 11、DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
* * 12、ImageSpan 图片
* * 13、RelativeSizeSpan 相对大小(文本字体)
* * 14、ReplacementSpan 父类,一般不用
* * 15、ScaleXSpan 基于x轴缩放
* * 16、StyleSpan 字体样式:粗体、斜体等
* * 17、SubscriptSpan 下标(数学公式会用到)
* * 18、SuperscriptSpan 上标(数学公式会用到)
* * 19、TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
* * 20、TypefaceSpan 文本字体
* * 21、URLSpan 文本超链接
* *
*
*/
class UISpanActivity : AppCompatActivity() {
companion object {
fun startActivity(context: Context) {
context.startActivity(Intent(context, UISpanActivity::class.java))
}
}
val binding: ActivityUiSpanBinding by lazy {
ActivityUiSpanBinding.inflate(LayoutInflater.from(this))
}
private fun getGradientSpan(content: String, startColor: Int, endColor: Int, isLeftToRight: Boolean): SpannableStringBuilder {
val spannableStringBuilder = SpannableStringBuilder(content)
val span = KtLinearGradientFontSpan(startColor, endColor, isLeftToRight)
spannableStringBuilder.setSpan(span, 0, spannableStringBuilder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
// 若有需要可以在这里用SpanString系列的其他类,给文本添加下划线、超链接、删除线...等等效果
return spannableStringBuilder
}
@RequiresApi(Build.VERSION_CODES.P)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btFinish.setOnClickListener {
finish()
}
// 自定义颜色
val customColor = Color.parseColor("#FF5722")
// 自定义图片资源,假设你在 res/drawable 目录下有一张名为 ic_example 的图片
val customDrawableResId = android.R.drawable.star_big_on
val typeface = ResourcesCompat.getFont(this, R.font.alimama_shu_hei_ti_bold);
val spanUtils = SpanUtils.getInstance(this)
binding.tv01.text="设置字体"
binding.tv01.setTypeface(typeface)
binding.tv02.setTypeface(typeface)
binding.tv02.setText(
getGradientSpan(
"修改字体渐变色", getColor(R.color.color_start), getColor(R.color.color_end),
true
), TextView.BufferType.SPANNABLE
)
spanUtils.appendSpannableToTextView(binding.tv1, spanUtils.setTextTypeface( "起始文本 ",
"设置字体渐变色",
" 结束文本",getColor(R.color.color_start), getColor(R.color.color_end),true))
// 1. 设置背景色
val backgroundColorSpannable = spanUtils.setBackgroundColorSpan(
"起始文本 ",
"背景色文本",
" 结束文本",
customColor
)
spanUtils.appendSpannableToTextView(binding.tv1, backgroundColorSpannable)
// 2. 设置可点击文本
val clickableSpannable = spanUtils.setClickableSpan(
"起始文本",
"点击我弹出吐司",
"起始文本",
{ content ->
Toast.makeText(this@UISpanActivity, content, Toast.LENGTH_SHORT).show()
}
)
spanUtils.appendSpannableToTextView(binding.tv2, clickableSpannable)
// 开启 TextView 的可点击和可触摸事件
binding.tv2.isClickable = true
binding.tv2.isFocusable = true
// 设置 MovementMethod 以处理点击事件
binding.tv2.movementMethod = android.text.method.LinkMovementMethod.getInstance()
// 3. 设置前景色
val foregroundColorSpannable = spanUtils.setForegroundColorSpan(
"起始文本 ",
"前景色文本",
" 结束文本",
customColor
)
spanUtils.appendSpannableToTextView(binding.tv3, foregroundColorSpannable)
// 4. 设置修饰效果(模糊和浮雕)
binding.tv4.setLayerType(TextView.LAYER_TYPE_SOFTWARE, null)
val maskFilterSpannable = spanUtils.setMaskFilterSpan(
"起始文本 ",
"修饰效果文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv4, maskFilterSpannable)
// 5. 设置删除线
val strikethroughSpannable = spanUtils.setStrikethroughSpan(
"起始文本 ",
"删除线文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv5, strikethroughSpannable)
// 6. 设置下划线
val underlineSpannable = spanUtils.setUnderlineSpan(
"起始文本 ",
"下划线文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv6, underlineSpannable)
// 7. 设置绝对大小
val absoluteSizeSpannable = spanUtils.setAbsoluteSizeSpan(
"起始文本 ",
"绝对大小文本",
" 结束文本",
24
)
spanUtils.appendSpannableToTextView(binding.tv7, absoluteSizeSpannable)
// 8. 设置动态图片(基于文本基线或底部对齐)
val dynamicDrawableSpannable = spanUtils.setDynamicDrawableSpan(
"起始文本 ",
"动态图片文本",
" 结束文本",
customDrawableResId,
100,
100
)
spanUtils.appendSpannableToTextView(binding.tv8, dynamicDrawableSpannable)
// 9. 设置图片
val imageSpannable = spanUtils.setImageSpan(
"起始文本 ",
"图片文本",
" 结束文本",
customDrawableResId,
100,
100
)
spanUtils.appendSpannableToTextView(binding.tv9, imageSpannable)
// 10. 设置相对大小
val relativeSizeSpannable = spanUtils.setRelativeSizeSpan(
"起始文本 ",
"相对大小文本",
" 结束文本",
1.5f
)
spanUtils.appendSpannableToTextView(binding.tv10, relativeSizeSpannable)
// 11. 基于 x 轴缩放
val scaleXSpannable = spanUtils.setScaleXSpan(
"起始文本 ",
"x 轴缩放文本",
" 结束文本",
2f
)
spanUtils.appendSpannableToTextView(binding.tv11, scaleXSpannable)
// 12. 设置字体样式
val styleSpannable = spanUtils.setStyleSpan(
"起始文本 ",
"字体样式文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv12, styleSpannable)
// 13. 设置下标
val subscriptSpannable = spanUtils.setSubscriptSpan(
"起始文本 ",
"下标文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv13, subscriptSpannable)
// 14. 设置上标
val superscriptSpannable = spanUtils.setSuperscriptSpan(
"起始文本 ",
"上标文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv14, superscriptSpannable)
// 15. 设置文本外貌
val textAppearanceSpannable = spanUtils.setTextAppearanceSpan(
"起始文本 ",
"文本外貌文本",
" 结束文本"
)
spanUtils.appendSpannableToTextView(binding.tv15, textAppearanceSpannable)
val tp= ResourcesCompat.getFont(this, R.font.alimama_shu_hei_ti_bold)
if (tp!=null){
// 16. 设置字体
val typefaceSpannable = spanUtils.setTypefaceSpan(
"起始文本 ",
"字体文本",
" 结束文本",tp
)
spanUtils.appendSpannableToTextView(binding.tv16, typefaceSpannable)
}
// 17. 设置超链接
val urlSpannable = spanUtils.setURLSpan(
"起始文本 ",
"超链接文本",
" 结束文本",
"https://www.example.com"
)
spanUtils.appendSpannableToTextView(binding.tv17, urlSpannable)
binding.tv1.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv2.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv3.movementMethod = android.text.method.LinkMovementMethod.getInstance()
// binding.tv4.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv5.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv6.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv7.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv8.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv9.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv10.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv11.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv12.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv13.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv14.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv15.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv16.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv17.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv18.movementMethod = android.text.method.LinkMovementMethod.getInstance()
binding.tv19.movementMethod = android.text.method.LinkMovementMethod.getInstance()
}
}
总结
Android 提供了强大的Span 支持对TextView文本进行操作,这里对设置颜色
,背景
,点击事件
,字体渐变
,图文混合
,下划线
,中划线
,模糊效果
,超文本
等效果一一实现,以此记录方便后续copy.