Skip to content

Commit 9ea08ff

Browse files
committed
1,新增支持渐变色字体
1 parent 5e668e4 commit 9ea08ff

File tree

7 files changed

+201
-23
lines changed

7 files changed

+201
-23
lines changed

FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatText.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class FormatText : BaseFormat() {
5151
@JvmField
5252
var ignorePaintShader = true
5353

54+
@JvmField
55+
var gradient: Gradient? = null
56+
5457

5558
fun setTextColor(@ColorRes color: Int): FormatText {
5659
this.textColor = color
@@ -128,4 +131,9 @@ class FormatText : BaseFormat() {
128131
return this
129132
}
130133

134+
fun setIgnorePaintShader(gradient: Gradient): FormatText {
135+
this.gradient = gradient
136+
return this
137+
}
138+
131139
}

FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatTextView.kt

Lines changed: 152 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package com.flyjingfish.formattextview
22

33
import android.content.Context
4-
import android.graphics.*
4+
import android.graphics.Canvas
5+
import android.graphics.Color
6+
import android.graphics.LinearGradient
7+
import android.graphics.Paint
8+
import android.graphics.Rect
9+
import android.graphics.RectF
10+
import android.graphics.Shader
11+
import android.graphics.Typeface
512
import android.graphics.drawable.Drawable
613
import android.graphics.drawable.InsetDrawable
714
import android.graphics.drawable.LevelListDrawable
@@ -16,7 +23,7 @@ import android.util.LayoutDirection
1623
import android.view.View
1724
import androidx.annotation.StringRes
1825
import androidx.core.text.TextUtilsCompat
19-
import java.util.*
26+
import java.util.Locale
2027

2128

2229
class FormatTextView : BaseTextView {
@@ -25,8 +32,13 @@ class FormatTextView : BaseTextView {
2532
private var onInflateImageListener: OnInflateImageListener? = null
2633
private var isClickSpanItem = false
2734
var isSetOnClick = false
35+
private var isDrawGradient = false
2836
private val underLineTexts: ArrayList<LineText> = ArrayList()
2937
private val deleteLineTexts: ArrayList<LineText> = ArrayList()
38+
private val gradientTexts: ArrayList<LineText> = ArrayList()
39+
private val gradientDrawTexts: ArrayList<GradientText> = ArrayList()
40+
private var formatArgs: Array<out BaseFormat?>? = null
41+
private var richText: String ?= null
3042

3143
constructor(context: Context) : super(context)
3244
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
@@ -45,6 +57,7 @@ class FormatTextView : BaseTextView {
4557
textValue = textValue.replace("\\n".toRegex(), "<br>")
4658
textValue = textValue.replace("\\r".toRegex(), "<br>")
4759
val strings = arrayOfNulls<String>(args.size)
60+
var isContainGradient = false
4861
for (i in args.indices) { //%1$s
4962
val start = "<a href=\"$i\">"
5063
val end = "</a>"
@@ -64,17 +77,29 @@ class FormatTextView : BaseTextView {
6477
value1 = value1?.replace("\\n".toRegex(), "<br>")
6578
value1 = value1?.replace("\\r".toRegex(), "<br>")
6679
strings[i] = start + value1 + end
80+
if (formatText.gradient != null){
81+
isContainGradient = true
82+
}
6783
}
6884

6985

7086
}
7187
val richText = String.format(textValue, *strings)
72-
88+
formatArgs = args
89+
this.richText = richText
90+
isDrawGradient = !isContainGradient
91+
underLineTexts.clear()
92+
deleteLineTexts.clear()
93+
gradientTexts.clear()
94+
gradientDrawTexts.clear()
7395
text = getCustomStyleHtml(richText, *args)
7496
highlightColor = Color.TRANSPARENT
7597
autoLinkMask = Linkify.WEB_URLS
7698
}
7799

100+
private fun resetText(){
101+
text = richText?.let { formatArgs?.let { it1 -> getCustomStyleHtml(it, *it1) } }
102+
}
78103

79104
fun setFormatText(@StringRes formatTextRes: Int, vararg args: Int) {
80105
setFormatText(resources.getString(formatTextRes), *args)
@@ -299,11 +324,83 @@ class FormatTextView : BaseTextView {
299324
userDefaultDelete = false
300325

301326
}
327+
//gradient
328+
if (!isDrawGradient && formatText.gradient != null) {
329+
val textPaint = TextPaint()
330+
textPaint.textSize = if (textSize > 0) sp2px(context, textSize) else getTextSize()
331+
val fm = textPaint.fontMetrics
332+
333+
val gradientText = LineText(
334+
start,
335+
end,
336+
0,
337+
(fm.descent - fm.ascent) / 2 - fm.descent,
338+
0f
339+
)
340+
gradientTexts.add(gradientText)
341+
342+
}
343+
344+
if (isDrawGradient && gradientDrawTexts.size > 0){
345+
for (gradientDrawText in gradientDrawTexts) {
346+
if (gradientDrawText.start>=start && gradientDrawText.end <= end){
347+
348+
val clickableSpan: GradientSpan = object : GradientSpan() {
349+
override fun updateDrawState(ds: TextPaint) {
350+
super.updateDrawState(ds)
351+
var left=0f
352+
var top=0f
353+
var right=0f
354+
var bottom=0f
355+
var orientation = formatText.gradient?.orientation
356+
if (orientation == null){
357+
orientation = Gradient.Orientation.LEFT_TO_RIGHT
358+
}
359+
when (orientation) {
360+
Gradient.Orientation.LEFT_TO_RIGHT -> {
361+
left = gradientDrawText.rectF.left
362+
top = gradientDrawText.rectF.top
363+
right = gradientDrawText.rectF.right
364+
bottom = gradientDrawText.rectF.top
365+
}
366+
Gradient.Orientation.TOP_TO_BOTTOM -> {
367+
left = gradientDrawText.rectF.left
368+
top = gradientDrawText.rectF.top
369+
right = gradientDrawText.rectF.left
370+
bottom = gradientDrawText.rectF.bottom
371+
}
372+
Gradient.Orientation.LEFT_TOP_TO_RIGHT_BOTTOM -> {
373+
left = gradientDrawText.rectF.left
374+
top = gradientDrawText.rectF.top
375+
right = gradientDrawText.rectF.right
376+
bottom = gradientDrawText.rectF.bottom
377+
}
378+
Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP -> {
379+
left = gradientDrawText.rectF.left
380+
top = gradientDrawText.rectF.bottom
381+
right = gradientDrawText.rectF.right
382+
bottom = gradientDrawText.rectF.top
383+
}
384+
}
385+
val mLinearGradient = formatText.gradient?.gradientColors?.let {
386+
LinearGradient(
387+
left, top, right, bottom,
388+
it, formatText.gradient?.gradientPositions,
389+
Shader.TileMode.CLAMP
390+
)
391+
}
392+
ds.shader = mLinearGradient
393+
}
394+
}
395+
htmlBuilder.setSpan(clickableSpan, gradientDrawText.start, gradientDrawText.end, flags)
396+
}
397+
}
398+
}
302399

303400
val clickableSpan: ClickableSpan = object : FormatClickableSpan(urlSpan) {
304401
override fun updateDrawState(ds: TextPaint) {
305402
super.updateDrawState(ds)
306-
if(formatText.ignorePaintShader){
403+
if(formatText.ignorePaintShader && formatText.gradient == null){
307404
ds.shader = null
308405
}
309406
//设置颜色
@@ -361,6 +458,13 @@ class FormatTextView : BaseTextView {
361458
}
362459
}
363460

461+
abstract class GradientSpan : CharacterStyle(), UpdateAppearance {
462+
override fun updateDrawState(ds: TextPaint) {
463+
ds.color = ds.linkColor
464+
ds.isUnderlineText = false
465+
}
466+
}
467+
364468
override fun setOnClickListener(l: OnClickListener?) {
365469
// 为了处理ClickableSpan和View.OnClickListener点击事件冲突
366470
super.setOnClickListener {
@@ -382,8 +486,46 @@ class FormatTextView : BaseTextView {
382486
super.onDraw(canvas)
383487
drawUnderline(canvas)
384488
drawDeleteLine(canvas)
489+
getGradient()
385490
}
491+
private fun getGradient() {
492+
if (gradientTexts.size == 0 || isDrawGradient) {
493+
return
494+
}
495+
//绘制下划线
496+
for (lineText in gradientTexts) {
497+
val map = HashMap<Int,GradientText>()
498+
for (i in lineText.start until lineText.end) {
499+
val line = layout.getLineForOffset(i)
500+
val bound = getUnderLineBound(i)
501+
val left = bound.left.toFloat()
502+
val top = bound.bottom.toFloat() - lineText.lineTop*2
503+
val right = bound.right.toFloat()
504+
val bottom = bound.bottom.toFloat()
505+
val rect = RectF(left,top,right, bottom)
506+
if (!map.containsKey(line)){
507+
val gradientText = GradientText(rect,i,i+1)
508+
map[line] = gradientText
509+
}else{
510+
val gradientText = map[line]
511+
val oldRect = gradientText!!.rectF
512+
if (oldRect.left < rect.left){
513+
oldRect.right = right
514+
}else{
515+
oldRect.left = left
516+
}
517+
gradientText.end = i+1
518+
}
519+
}
386520

521+
for ((_,value) in map){
522+
gradientDrawTexts.add(value)
523+
}
524+
525+
}
526+
isDrawGradient = true
527+
resetText()
528+
}
387529
private fun drawUnderline(canvas: Canvas?) {
388530
if (underLineTexts.size == 0) {
389531
return
@@ -476,6 +618,12 @@ class FormatTextView : BaseTextView {
476618
var lineWidth: Float
477619
)
478620

621+
private class GradientText(
622+
var rectF: RectF,
623+
var start: Int,
624+
var end: Int,
625+
)
626+
479627
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
480628
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
481629
if (underLineTexts.size > 0) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.flyjingfish.formattextview
2+
3+
class Gradient(
4+
var gradientColors: IntArray,
5+
var gradientPositions: FloatArray?,
6+
var orientation: Orientation?
7+
) {
8+
enum class Orientation{
9+
LEFT_TO_RIGHT,
10+
TOP_TO_BOTTOM,
11+
LEFT_TOP_TO_RIGHT_BOTTOM,
12+
LEFT_BOTTOM_TO_RIGHT_TOP
13+
}
14+
}

README-zh.md

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
```gradle
5353
dependencies {
54-
implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.3'
54+
implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.4'
5555
}
5656
```
5757
## 第三步,使用说明
@@ -204,22 +204,24 @@ textView.setFormatTextBean("%1$s欢迎欢迎欢迎欢迎欢迎欢迎欢迎%3$s
204204
ALIGN_CENTER 为当前库新增对齐方式旨解决在小图标和文本中心对齐问题,在图片设置超过行高时将会出现裁剪问题,如果您图片很大还是建议使用ALIGN_BASELINE
205205

206206
## FormatText 参数一览
207-
| 属性 | 参数类型 | 描述 |
208-
|--------------------|:--------------:|:-------------:|
209-
| textColor | @ColorRes int | 文字资源颜色Id |
210-
| bold | boolean | 文字是否加粗 |
211-
| italic | boolean | 文字是否斜体 |
212-
| strValue | String | 文字String类型值 |
213-
| resValue | @StringRes int | 文字文本资源Id |
214-
| textSize | float | 文字字体大小(单位:SP) |
215-
| underline | boolean | 文字是否下划线 |
216-
| underlineColor | @ColorRes int | 文字下划线颜色 |
217-
| underlineWidth | float | 文字下划线线宽 |
218-
| underlineMarginTop | float | 文字下划线向下偏移的距离 |
219-
| deleteLine | boolean | 文字是否删除线 |
220-
| deleteLineColor | @ColorRes int | 文字删除线颜色 |
221-
| deleteLineWidth | float | 文字删除线线宽 |
222-
| backgroundColor | @ColorRes int | 文字区域背景色 |
207+
| 属性 | 参数类型 | 描述 |
208+
|--------------------|:--------------:|:---------------------:|
209+
| textColor | @ColorRes int | 文字资源颜色Id |
210+
| bold | boolean | 文字是否加粗 |
211+
| italic | boolean | 文字是否斜体 |
212+
| strValue | String | 文字String类型值 |
213+
| resValue | @StringRes int | 文字文本资源Id |
214+
| textSize | float | 文字字体大小(单位:SP) |
215+
| underline | boolean | 文字是否下划线 |
216+
| underlineColor | @ColorRes int | 文字下划线颜色 |
217+
| underlineWidth | float | 文字下划线线宽 |
218+
| underlineMarginTop | float | 文字下划线向下偏移的距离 |
219+
| deleteLine | boolean | 文字是否删除线 |
220+
| deleteLineColor | @ColorRes int | 文字删除线颜色 |
221+
| deleteLineWidth | float | 文字删除线线宽 |
222+
| backgroundColor | @ColorRes int | 文字区域背景色 |
223+
| ignorePaintShader | boolean | 文字是否忽略TextView的Shader |
224+
| gradient | Gradient | 文字渐变色配置 |
223225

224226
## FormatImage 参数一览
225227
| 属性 | 参数类型 | 描述 |

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
5454
```gradle
5555
dependencies {
56-
implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.3'
56+
implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.4'
5757
}
5858
````
5959
## The third step, instructions for use
@@ -222,6 +222,8 @@ ALIGN_CENTER adds an alignment method to the current library to solve the alignm
222222
| deleteLineColor | @ColorRes int | Text strikethrough color |
223223
| deleteLineWidth | float | Text strikethrough line width |
224224
| backgroundColor | @ColorRes int | Text area background color |
225+
| ignorePaintShader | boolean | Whether the text ignores the Shader of the TextView |
226+
| gradient | Gradient | Text Gradient Color Configuration |
225227

226228
## FormatImage parameter list
227229
| property | parameter type | description |

app/src/main/java/com/flyjingfish/formattextviewdemo/DemoActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.flyjingfish.formattextviewdemo
22

3+
import android.graphics.Color
34
import android.graphics.LinearGradient
45
import android.graphics.Shader
56
import android.graphics.drawable.Drawable
@@ -30,6 +31,7 @@ class DemoActivity : AppCompatActivity() {
3031
underlineMarginTop = 6f
3132
underlineWidth = 2f
3233
resValue = R.string.User_Agreement
34+
gradient = Gradient(intArrayOf(Color.GREEN,Color.RED),null,Gradient.Orientation.LEFT_TO_RIGHT)
3335
},
3436
FormatText().apply {
3537
textSize = 22f
@@ -41,6 +43,7 @@ class DemoActivity : AppCompatActivity() {
4143
underlineMarginTop = 6f
4244
underlineWidth = 2f
4345
resValue = R.string.Privacy_Policy
46+
gradient = Gradient(intArrayOf(Color.BLUE,Color.RED),null,Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP)
4447
}
4548
)
4649
text1.setOnFormatClickListener(object :OnFormatClickListener{
@@ -104,6 +107,7 @@ class DemoActivity : AppCompatActivity() {
104107
underlineMarginTop = 10f
105108
underlineWidth = 3f
106109
ignorePaintShader = false
110+
gradient = Gradient(intArrayOf(Color.BLUE,Color.RED),null,Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP)
107111
},
108112
FormatText().apply {
109113
textSize = 30f

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
android:text="Hello World!" />
1717

1818

19-
<com.flyjingfish.formattextview.FormatTextView
19+
<TextView
2020
android:layout_width="wrap_content"
2121
android:layout_height="wrap_content"
2222
android:textSize="18sp"

0 commit comments

Comments
 (0)