Skip to content

Commit e8a2628

Browse files
committed
[1.7.0-feature] Span系列示例
1 parent 1e8de6f commit e8a2628

File tree

3 files changed

+105
-67
lines changed

3 files changed

+105
-67
lines changed

app/src/main/kotlin/org/ninetripods/mq/study/activity/SpanStudyActivity.kt

Lines changed: 101 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package org.ninetripods.mq.study.activity
22

3-
import android.graphics.BlurMaskFilter
4-
import android.graphics.Color
5-
import android.graphics.Typeface
3+
import android.graphics.*
64
import android.os.Build
7-
import android.text.Layout
85
import android.text.SpannableStringBuilder
96
import android.text.Spanned
107
import android.text.method.LinkMovementMethod
@@ -27,6 +24,9 @@ class SpanStudyActivity : BaseActivity() {
2724
const val TITLE_2 =
2825
"---> 2、影响度量的Span,实现UpdateLayout接口(UpdateLayout->UpdateAppearance),继承MetricAffectingSpan(MetricAffectingSpan->CharacterStyle)\n"
2926
const val TITLE_3 = "---> 3、影响段落的Span \n"
27+
// const val TITLE_1 = ""
28+
// const val TITLE_2 = ""
29+
// const val TITLE_3 = ""
3030

3131
private const val SPAN_STR: String = TITLE_1 +
3232
"北国风光,千里冰封,万里雪飘。\n\n" +
@@ -35,7 +35,8 @@ class SpanStudyActivity : BaseActivity() {
3535
"须晴日,看红装素裹,_ 分外妖娆。\n\n江山如此多娇,引无数英雄竞折腰。\n\n" +
3636
"惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。\n\n" +
3737
TITLE_3 +
38-
"一代天骄,成吉思汗,只识弯弓射大雕。\n\n" + " 俱往矣,数风流人物,还看今朝。"
38+
"一代天骄,成吉思汗,只识弯弓射大雕。\n\n" + "俱往矣,数风流人物,还看今朝。"
39+
private const val SPAN_STR2 = "锄禾日当午,\n\t汗滴禾下土。\n谁知盘中餐,\n\t粒粒皆辛苦。"
3940
const val SEG_1 = "北国风光"
4041
const val SEG_2 = "千里冰封"
4142
const val SEG_3 = "万里雪飘"
@@ -60,10 +61,10 @@ class SpanStudyActivity : BaseActivity() {
6061
const val SEG_22 = "只识弯弓射大雕"
6162
const val SEG_23 = "俱往矣"
6263
const val SEG_24 = "数风流人物"
63-
const val SEG_25 = "还看今朝"
64+
const val SEG_25 = "还看今朝"
6465
const val ORIGIN_FLAGS = "01234"
6566

66-
val finalStr = SPAN_STR.replace(SEG_3, "万里雪飘 ")
67+
val finalStr = SPAN_STR.replace(SEG_3, "万里雪飘")
6768
val index1 = finalStr.indexOf(SEG_1)
6869
val index2 = finalStr.indexOf(SEG_2)
6970
val index3 = finalStr.indexOf(SEG_3)
@@ -118,14 +119,13 @@ class SpanStudyActivity : BaseActivity() {
118119
processAppearance(spanBuilder)
119120
//2、影响度量的Span,实现UpdateLayout接口(UpdateLayout->UpdateAppearance),
120121
// 继承MetricAffectingSpan(MetricAffectingSpan->CharacterStyle)
121-
processMetrics(spanBuilder)
122+
// processMetrics(spanBuilder)
122123
//3、影响段落的Span
123-
processParagraph(spanBuilder)
124+
// processParagraph(spanBuilder)
124125

125-
tvSpan.highlightColor = Color.TRANSPARENT
126126
tvSpan.movementMethod = LinkMovementMethod.getInstance()
127127
tvSpan.text = spanBuilder
128-
tvSpan.setText(spanBuilder, TextView.BufferType.SPANNABLE)
128+
// tvSpan.setText(spanBuilder, TextView.BufferType.SPANNABLE)
129129
tvSpan.setOnClickListener {
130130
//避免ClickSpan与TextView本身同时相应点击事件
131131
(it as? TextView)?.let { tv ->
@@ -250,6 +250,7 @@ class SpanStudyActivity : BaseActivity() {
250250
index12, index12 + SEG_12.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
251251
)
252252

253+
//ImageSpan
253254
val imgDrawable =
254255
ResourcesCompat.getDrawable(resources, R.drawable.icon_flower, null)
255256
imgDrawable?.let {
@@ -259,13 +260,18 @@ class SpanStudyActivity : BaseActivity() {
259260
index13, index13 + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
260261
)
261262
}
263+
262264
//自定义RelativeSizeSpan
263265
spanBuilder.setSpan(
264266
RelativeSizeColorSpan(0.8f, Color.RED),
265267
index14, index14 + SEG_14.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
266268
)
267269

268270
spanBuilder.setSpan(
271+
/**
272+
* @param size 文本的绝对值大小,单位是像素px
273+
* @param dip 如果为true,则size变以为dp为单位;否则还是以像素px为单位。
274+
*/
269275
AbsoluteSizeSpan(20, true),
270276
index15, index15 + SEG_15.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
271277
)
@@ -296,64 +302,105 @@ class SpanStudyActivity : BaseActivity() {
296302
private fun processParagraph(spanBuilder: SpannableStringBuilder) {
297303
spanBuilder.setSpan(
298304
/**
299-
* first: 每一个段落的首行缩进
300-
* mRest: 每一个段落的其他行缩进
305+
* first: 每个段落的首行缩进
306+
* mRest: 每个段落的其他行缩进
301307
*/
302308
LeadingMarginSpan.Standard(20.dp2px(), 5.dp2px()),
303309
0, SPAN_STR.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
304310
)
311+
305312
//LineBackgroundSpan改变行的背景色,如果[start,end)不够一行按一行处理
306-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
307-
spanBuilder.setSpan(
308-
LineBackgroundSpan.Standard(Color.YELLOW),
309-
index20, index20 + SEG_20.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
310-
)
311-
}
313+
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
314+
// spanBuilder.setSpan(
315+
// LineBackgroundSpan.Standard(Color.YELLOW),
316+
// 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
317+
// )
318+
// }
319+
312320
//LineHeightSpan改变段落的行高
313-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
314-
//注意,LineHeightSpan将改变整个段落的行高,即使它只覆盖段落的一部分。
315-
spanBuilder.setSpan(
316-
LineHeightSpan.Standard(30.dp2px()),
317-
index21, index21 + SEG_21.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
318-
)
319-
}
321+
// spanBuilder.clear()
322+
// spanBuilder.append(SPAN_STR2)
323+
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
324+
// //注意,LineHeightSpan将改变整个段落的行高,即使它只覆盖段落的一部分。
325+
// spanBuilder.setSpan(
326+
// LineHeightSpan.Standard(20.dp2px()),
327+
// 0, SPAN_STR2.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
328+
// )
329+
// }
320330

321-
//在文本的行首添加一个带有指定边距的 Drawable TODO IconMarginSpan vs DrawableMarginSpan如何使用
322-
// val imgDrawable =
323-
// ResourcesCompat.getDrawable(resources, R.drawable.icon_flower, null).apply {
324-
// this?.setBounds(0, 0, 20.dp2px(), 20.dp2px())
325-
// }
331+
//在文本的行首添加一个带有指定边距的 Drawable
332+
// val imgDrawable = ResourcesCompat.getDrawable(resources, R.drawable.icon_arrow_pull, null)
326333
// spanBuilder.setSpan(
327-
// IconMarginSpan(BitmapFactory.decodeResource(resources, R.drawable.icon_flower), 10.sp2px()),
334+
// IconMarginSpan(
335+
// BitmapFactory.decodeResource(resources, R.drawable.icon_arrow_pull), 10.sp2px()
336+
// ),
328337
// //DrawableMarginSpan(imgDrawable!!, 10.sp2px()),
329-
// index22, index22 + SEG_22.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
338+
// 0, SPAN_STR.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
330339
// )
331340

332-
//QuoteSpan给文本添加引用样式。
333-
//注意:必须从一个段落的第一个字符连接到最后一个字符,否则不会显示该span。
334-
spanBuilder.setSpan(
335-
QuoteSpan(Color.RED),
336-
index23 - 1, SPAN_STR.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
337-
)
341+
//QuoteSpan可以在文本开始的地方添加引用样式(一个垂直的线条)。
342+
// val quoteSpan = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
343+
// /**
344+
// * QuoteSpan(int color, int stripeWidth, int gapWidth)
345+
// * @param color 垂直线条颜色。缺省情况下,条带颜色为0xff0000ff
346+
// * @param stripeWidth 线条的宽度,以像素为单位。默认值是2px。
347+
// * @param gapWidth 线条和段落之间的距离,以像素为单位。默认值是2px。
348+
// */
349+
// QuoteSpan(Color.RED, 20, 40)
350+
// } else {
351+
// QuoteSpan(Color.RED)
352+
// }
353+
// spanBuilder.setSpan(quoteSpan,
354+
// 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
355+
// )
338356

339-
//给文本添加项目符号样式 TODO
340-
spanBuilder.setSpan(
341-
BulletSpan(20, 0xCE6454A),
342-
index24, index24 + SEG_24.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
343-
)
344357

345-
//AlignmentSpan
346-
spanBuilder.setSpan(
347-
AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE),
348-
index25, index25 + SEG_25.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
349-
)
358+
//给文本添加圆点符号
359+
//第一行设置圆点
360+
// spanBuilder.setSpan( getBulletSpan(),
361+
// 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
362+
// val index23 = SPAN_STR.indexOf(SEG_23)
363+
// //最后一行设置圆点
364+
// spanBuilder.setSpan( getBulletSpan(),
365+
// index23, index23 + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
366+
// )
367+
/**
368+
* AlignmentSpan文本对齐方式
369+
*/
370+
// spanBuilder.setSpan(
371+
// /**
372+
// * AlignmentSpan.Standard(Layout.Alignment align)
373+
// * align: Layout.Alignment类型的枚举值。包括三种情况:
374+
// * 1、ALIGN_CENTER 居中、
375+
// * 2、ALIGN_NORMAL 正常、
376+
// * 3、ALIGN_OPPOSITE相反方向。
377+
// */
378+
// AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER),
379+
// 0, SPAN_STR.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
380+
// )
350381

351-
//TabStopSpan
352-
spanBuilder.setSpan(
353-
TabStopSpan.Standard(20.dp2px()),
354-
index25, index25 + SEG_25.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
355-
)
382+
//TabStopSpan 段落中第一行的左侧偏移量(与\t有关系),默认实现为TabStopSpan.Standard
383+
// spanBuilder.clear()
384+
// spanBuilder.append(SPAN_STR2)
385+
// spanBuilder.setSpan(
386+
// TabStopSpan.Standard(40.dp2px()),
387+
// 0, SPAN_STR2.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
388+
// )
389+
390+
}
356391

392+
private fun getBulletSpan(): BulletSpan {
393+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
394+
/**
395+
* BulletSpan(int gapWidth, int color, int bulletRadius)
396+
* @param gapWidth: 项目符号和段落之间的距离,单位是px,默认2px
397+
* @param color:项目符号颜色,默认是文本颜色
398+
* @param bulletRadius:符号半径,单位是px,默认是4px
399+
*/
400+
BulletSpan(20, Color.RED, 10)
401+
} else {
402+
BulletSpan(20, Color.RED)
403+
}
357404
}
358405

359406
private fun getSpanFlagStr(

app/src/main/kotlin/org/ninetripods/mq/study/span/RelativeSizeColorSpan.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.ninetripods.mq.study.span
22

33
import android.graphics.Color
4-
import android.graphics.Typeface
54
import android.text.TextPaint
65
import android.text.style.RelativeSizeSpan
76
import androidx.annotation.ColorInt
@@ -21,13 +20,4 @@ class RelativeSizeColorSpan(size: Float, @ColorInt val color: Int = Color.GRAY)
2120
paint.color = color
2221
paint.isUnderlineText = true
2322
}
24-
25-
/**
26-
*在测量文本时更新样式的测量状态,例如文本大小、字体等。
27-
*/
28-
override fun updateMeasureState(paint: TextPaint) {
29-
super.updateMeasureState(paint)
30-
paint.typeface = Typeface.DEFAULT_BOLD
31-
32-
}
3323
}

app/src/main/res/layout/activity_span_study.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
android:id="@+id/tv_span_flag"
2222
android:layout_width="match_parent"
2323
android:layout_height="wrap_content"
24-
android:layout_marginTop="50dp"
25-
android:layout_marginBottom="50dp"
24+
android:layout_marginTop="10dp"
25+
android:layout_marginBottom="20dp"
2626
android:lineSpacingExtra="6dp"
2727
android:paddingStart="20dp"
2828
android:paddingEnd="20dp"
@@ -85,7 +85,8 @@
8585
android:layout_width="match_parent"
8686
android:layout_height="wrap_content"
8787
android:layout_marginTop="30dp"
88-
android:layout_marginBottom="50dp"
88+
android:layout_marginBottom="5dp"
89+
android:padding="10dp"
8990
android:textSize="16sp"
9091
android:background="@color/backgroud_gray"
9192
app:layout_constraintEnd_toEndOf="parent"

0 commit comments

Comments
 (0)