1
+ package org.ninetripods.mq.study.span
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Color
5
+ import android.graphics.Paint
6
+ import android.graphics.RectF
7
+ import android.text.style.ReplacementSpan
8
+ import org.ninetripods.mq.study.kotlin.ktx.dp2px
9
+ import org.ninetripods.mq.study.kotlin.ktx.log
10
+ import org.ninetripods.mq.study.kotlin.ktx.sp2px
11
+
12
+ /* *
13
+ * 自定义Tag Span
14
+ * Created by mq on 2023/7/31
15
+ *
16
+ * @property tagColor tag外框颜色
17
+ * @property tagRadius tag圆角半径
18
+ * @property tagStrokeWidth tag外框宽度
19
+ * @property tagMarginLeft tag外框左侧的margin
20
+ * @property tagMarginRight tag外框右侧的margin
21
+ * @property tagPadding tag内侧文字padding
22
+ * @property txtSize 文字大小
23
+ * @property txtColor 文字颜色
24
+ */
25
+ class TagSpan (
26
+ private val tagColor : Int = Color .RED ,
27
+ private val tagRadius : Float = 2 .dp2px().toFloat(),
28
+ private val tagStrokeWidth : Float = 1 .dp2px().toFloat(),
29
+ private val tagMarginLeft : Float = 0 .dp2px().toFloat(),
30
+ private val tagMarginRight : Float = 5 .dp2px().toFloat(),
31
+ private val tagPadding : Float = 2 .dp2px().toFloat(),
32
+ private val txtSize : Float = 14 .sp2px().toFloat(),
33
+ private val txtColor : Int = Color .RED ,
34
+ ) : ReplacementSpan() {
35
+
36
+ private var mSpanWidth = 0 // 包含了Span文字左右间距在内的宽度
37
+
38
+ /* *
39
+ * 返回Span的宽度。子类可以通过更新Paint.FontMetricsInt的属性来设置Span的高度。
40
+ * 如果Span覆盖了整个文本,并且高度没有设置,那么draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)方法将不会调用。
41
+ *
42
+ * @param paint Paint画笔
43
+ * @param text 当前文本
44
+ * @param start Span开始索引
45
+ * @param end Span结束索引
46
+ * @param fm Paint.FontMetricsInt,可能是空
47
+ * @return 返回Span的宽度
48
+ */
49
+ override fun getSize (
50
+ paint : Paint ,
51
+ text : CharSequence? ,
52
+ start : Int ,
53
+ end : Int ,
54
+ fm : Paint .FontMetricsInt ? ,
55
+ ): Int {
56
+ if (text.isNullOrEmpty()) return 0
57
+ paint.textSize = txtSize
58
+ // 测量包含了Span文字左右间距在内的宽度
59
+ mSpanWidth = (paint.measureText(text, start, end) + getTxtLeftW() + getTxtRightW()).toInt()
60
+ log(" getSize-> text:$text ,start:$start ,end:$end ,fm:$fm ,mSpanWidth:$mSpanWidth " )
61
+ return mSpanWidth
62
+ }
63
+
64
+ /* *
65
+ * 将Span绘制到Canvas中
66
+ *
67
+ * @param canvas Canvas画布
68
+ * @param text 当前文本
69
+ * @param start Span开始索引
70
+ * @param end Span结束索引
71
+ * @param x Edge of the replacement closest to the leading margin.
72
+ * @param top 行文字显示区域的Top
73
+ * @param y Baseline基线
74
+ * @param bottom 行文字显示区域的Bottom 当在XML中设置lineSpacingExtra时,这里也会受影响
75
+ * @param paint Paint画笔
76
+ */
77
+ override fun draw (
78
+ canvas : Canvas ,
79
+ text : CharSequence? ,
80
+ start : Int ,
81
+ end : Int ,
82
+ x : Float ,
83
+ top : Int ,
84
+ y : Int ,
85
+ bottom : Int ,
86
+ paint : Paint ,
87
+ ) {
88
+ log(" draw -> text:$text ,start:$start ,end:$end ,x:$x ,top:$top ,y:$y ,bottom:$bottom " )
89
+ if (text.isNullOrEmpty()) return
90
+ paint.run {
91
+ color = tagColor
92
+ isAntiAlias = true
93
+ isDither = true
94
+ style = Paint .Style .STROKE
95
+ strokeWidth = tagStrokeWidth
96
+ }
97
+ // 文字高度
98
+ val txtHeight = paint.fontMetricsInt.descent - paint.fontMetricsInt.ascent
99
+ // 1、绘制标签
100
+ val tagRect = RectF (
101
+ x + getTagLeft(), top.toFloat(),
102
+ x + mSpanWidth - tagMarginRight, (top + txtHeight).toFloat()
103
+ )
104
+ canvas.drawRoundRect(tagRect, tagRadius, tagRadius, paint)
105
+
106
+ // 2、绘制文字
107
+ paint.run {
108
+ color = txtColor
109
+ style = Paint .Style .FILL
110
+ }
111
+ // 计算Baseline绘制的Y坐标 ,计算方式:画布高度的一半 - 文字总高度的一半
112
+ val baseY = tagRect.height() / 2 - (paint.descent() + paint.ascent()) / 2
113
+ // 绘制标签内文字
114
+ canvas.drawText(text, start, end, x + getTxtLeftW(), baseY, paint)
115
+ }
116
+
117
+ private fun getTagLeft (): Float {
118
+ return tagMarginLeft + tagStrokeWidth
119
+ }
120
+
121
+ /* *
122
+ * Span文字左侧所有的间距
123
+ */
124
+ private fun getTxtLeftW (): Float {
125
+ return tagPadding + tagMarginLeft + tagStrokeWidth
126
+ }
127
+
128
+ /* *
129
+ * Span文字右侧所有的间距
130
+ */
131
+ private fun getTxtRightW (): Float {
132
+ return tagPadding + tagMarginRight + tagStrokeWidth
133
+ }
134
+ }
0 commit comments