From 9ea08ff072837c4364bd6ddcee1508f16a35d153 Mon Sep 17 00:00:00 2001 From: tianxiangyu <96164429+FlyJingFish@users.noreply.github.com> Date: Thu, 11 May 2023 13:50:18 +0800 Subject: [PATCH] =?UTF-8?q?1=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=B8=90=E5=8F=98=E8=89=B2=E5=AD=97=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flyjingfish/formattextview/FormatText.kt | 8 + .../formattextview/FormatTextView.kt | 156 +++++++++++++++++- .../flyjingfish/formattextview/Gradient.kt | 14 ++ README-zh.md | 36 ++-- README.md | 4 +- .../formattextviewdemo/DemoActivity.kt | 4 + app/src/main/res/layout/activity_demo.xml | 2 +- 7 files changed, 201 insertions(+), 23 deletions(-) create mode 100644 FormatTextView/src/main/java/com/flyjingfish/formattextview/Gradient.kt diff --git a/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatText.kt b/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatText.kt index b9bd4cf..e4c311f 100644 --- a/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatText.kt +++ b/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatText.kt @@ -51,6 +51,9 @@ class FormatText : BaseFormat() { @JvmField var ignorePaintShader = true + @JvmField + var gradient: Gradient? = null + fun setTextColor(@ColorRes color: Int): FormatText { this.textColor = color @@ -128,4 +131,9 @@ class FormatText : BaseFormat() { return this } + fun setIgnorePaintShader(gradient: Gradient): FormatText { + this.gradient = gradient + return this + } + } \ No newline at end of file diff --git a/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatTextView.kt b/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatTextView.kt index d960ea5..ff6b742 100644 --- a/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatTextView.kt +++ b/FormatTextView/src/main/java/com/flyjingfish/formattextview/FormatTextView.kt @@ -1,7 +1,14 @@ package com.flyjingfish.formattextview import android.content.Context -import android.graphics.* +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.Shader +import android.graphics.Typeface import android.graphics.drawable.Drawable import android.graphics.drawable.InsetDrawable import android.graphics.drawable.LevelListDrawable @@ -16,7 +23,7 @@ import android.util.LayoutDirection import android.view.View import androidx.annotation.StringRes import androidx.core.text.TextUtilsCompat -import java.util.* +import java.util.Locale class FormatTextView : BaseTextView { @@ -25,8 +32,13 @@ class FormatTextView : BaseTextView { private var onInflateImageListener: OnInflateImageListener? = null private var isClickSpanItem = false var isSetOnClick = false + private var isDrawGradient = false private val underLineTexts: ArrayList = ArrayList() private val deleteLineTexts: ArrayList = ArrayList() + private val gradientTexts: ArrayList = ArrayList() + private val gradientDrawTexts: ArrayList = ArrayList() + private var formatArgs: Array? = null + private var richText: String ?= null constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) @@ -45,6 +57,7 @@ class FormatTextView : BaseTextView { textValue = textValue.replace("\\n".toRegex(), "
") textValue = textValue.replace("\\r".toRegex(), "
") val strings = arrayOfNulls(args.size) + var isContainGradient = false for (i in args.indices) { //%1$s val start = "" val end = "" @@ -64,17 +77,29 @@ class FormatTextView : BaseTextView { value1 = value1?.replace("\\n".toRegex(), "
") value1 = value1?.replace("\\r".toRegex(), "
") strings[i] = start + value1 + end + if (formatText.gradient != null){ + isContainGradient = true + } } } val richText = String.format(textValue, *strings) - + formatArgs = args + this.richText = richText + isDrawGradient = !isContainGradient + underLineTexts.clear() + deleteLineTexts.clear() + gradientTexts.clear() + gradientDrawTexts.clear() text = getCustomStyleHtml(richText, *args) highlightColor = Color.TRANSPARENT autoLinkMask = Linkify.WEB_URLS } + private fun resetText(){ + text = richText?.let { formatArgs?.let { it1 -> getCustomStyleHtml(it, *it1) } } + } fun setFormatText(@StringRes formatTextRes: Int, vararg args: Int) { setFormatText(resources.getString(formatTextRes), *args) @@ -299,11 +324,83 @@ class FormatTextView : BaseTextView { userDefaultDelete = false } + //gradient + if (!isDrawGradient && formatText.gradient != null) { + val textPaint = TextPaint() + textPaint.textSize = if (textSize > 0) sp2px(context, textSize) else getTextSize() + val fm = textPaint.fontMetrics + + val gradientText = LineText( + start, + end, + 0, + (fm.descent - fm.ascent) / 2 - fm.descent, + 0f + ) + gradientTexts.add(gradientText) + + } + + if (isDrawGradient && gradientDrawTexts.size > 0){ + for (gradientDrawText in gradientDrawTexts) { + if (gradientDrawText.start>=start && gradientDrawText.end <= end){ + + val clickableSpan: GradientSpan = object : GradientSpan() { + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + var left=0f + var top=0f + var right=0f + var bottom=0f + var orientation = formatText.gradient?.orientation + if (orientation == null){ + orientation = Gradient.Orientation.LEFT_TO_RIGHT + } + when (orientation) { + Gradient.Orientation.LEFT_TO_RIGHT -> { + left = gradientDrawText.rectF.left + top = gradientDrawText.rectF.top + right = gradientDrawText.rectF.right + bottom = gradientDrawText.rectF.top + } + Gradient.Orientation.TOP_TO_BOTTOM -> { + left = gradientDrawText.rectF.left + top = gradientDrawText.rectF.top + right = gradientDrawText.rectF.left + bottom = gradientDrawText.rectF.bottom + } + Gradient.Orientation.LEFT_TOP_TO_RIGHT_BOTTOM -> { + left = gradientDrawText.rectF.left + top = gradientDrawText.rectF.top + right = gradientDrawText.rectF.right + bottom = gradientDrawText.rectF.bottom + } + Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP -> { + left = gradientDrawText.rectF.left + top = gradientDrawText.rectF.bottom + right = gradientDrawText.rectF.right + bottom = gradientDrawText.rectF.top + } + } + val mLinearGradient = formatText.gradient?.gradientColors?.let { + LinearGradient( + left, top, right, bottom, + it, formatText.gradient?.gradientPositions, + Shader.TileMode.CLAMP + ) + } + ds.shader = mLinearGradient + } + } + htmlBuilder.setSpan(clickableSpan, gradientDrawText.start, gradientDrawText.end, flags) + } + } + } val clickableSpan: ClickableSpan = object : FormatClickableSpan(urlSpan) { override fun updateDrawState(ds: TextPaint) { super.updateDrawState(ds) - if(formatText.ignorePaintShader){ + if(formatText.ignorePaintShader && formatText.gradient == null){ ds.shader = null } //设置颜色 @@ -361,6 +458,13 @@ class FormatTextView : BaseTextView { } } + abstract class GradientSpan : CharacterStyle(), UpdateAppearance { + override fun updateDrawState(ds: TextPaint) { + ds.color = ds.linkColor + ds.isUnderlineText = false + } + } + override fun setOnClickListener(l: OnClickListener?) { // 为了处理ClickableSpan和View.OnClickListener点击事件冲突 super.setOnClickListener { @@ -382,8 +486,46 @@ class FormatTextView : BaseTextView { super.onDraw(canvas) drawUnderline(canvas) drawDeleteLine(canvas) + getGradient() } + private fun getGradient() { + if (gradientTexts.size == 0 || isDrawGradient) { + return + } + //绘制下划线 + for (lineText in gradientTexts) { + val map = HashMap() + for (i in lineText.start until lineText.end) { + val line = layout.getLineForOffset(i) + val bound = getUnderLineBound(i) + val left = bound.left.toFloat() + val top = bound.bottom.toFloat() - lineText.lineTop*2 + val right = bound.right.toFloat() + val bottom = bound.bottom.toFloat() + val rect = RectF(left,top,right, bottom) + if (!map.containsKey(line)){ + val gradientText = GradientText(rect,i,i+1) + map[line] = gradientText + }else{ + val gradientText = map[line] + val oldRect = gradientText!!.rectF + if (oldRect.left < rect.left){ + oldRect.right = right + }else{ + oldRect.left = left + } + gradientText.end = i+1 + } + } + for ((_,value) in map){ + gradientDrawTexts.add(value) + } + + } + isDrawGradient = true + resetText() + } private fun drawUnderline(canvas: Canvas?) { if (underLineTexts.size == 0) { return @@ -476,6 +618,12 @@ class FormatTextView : BaseTextView { var lineWidth: Float ) + private class GradientText( + var rectF: RectF, + var start: Int, + var end: Int, + ) + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) if (underLineTexts.size > 0) { diff --git a/FormatTextView/src/main/java/com/flyjingfish/formattextview/Gradient.kt b/FormatTextView/src/main/java/com/flyjingfish/formattextview/Gradient.kt new file mode 100644 index 0000000..68aa8b3 --- /dev/null +++ b/FormatTextView/src/main/java/com/flyjingfish/formattextview/Gradient.kt @@ -0,0 +1,14 @@ +package com.flyjingfish.formattextview + +class Gradient( + var gradientColors: IntArray, + var gradientPositions: FloatArray?, + var orientation: Orientation? +) { + enum class Orientation{ + LEFT_TO_RIGHT, + TOP_TO_BOTTOM, + LEFT_TOP_TO_RIGHT_BOTTOM, + LEFT_BOTTOM_TO_RIGHT_TOP + } +} \ No newline at end of file diff --git a/README-zh.md b/README-zh.md index a9e821c..6f1322d 100644 --- a/README-zh.md +++ b/README-zh.md @@ -51,7 +51,7 @@ ```gradle dependencies { - implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.3' + implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.4' } ``` ## 第三步,使用说明 @@ -204,22 +204,24 @@ textView.setFormatTextBean("%1$s欢迎欢迎欢迎欢迎欢迎欢迎欢迎%3$s ALIGN_CENTER 为当前库新增对齐方式旨解决在小图标和文本中心对齐问题,在图片设置超过行高时将会出现裁剪问题,如果您图片很大还是建议使用ALIGN_BASELINE ## FormatText 参数一览 -| 属性 | 参数类型 | 描述 | -|--------------------|:--------------:|:-------------:| -| textColor | @ColorRes int | 文字资源颜色Id | -| bold | boolean | 文字是否加粗 | -| italic | boolean | 文字是否斜体 | -| strValue | String | 文字String类型值 | -| resValue | @StringRes int | 文字文本资源Id | -| textSize | float | 文字字体大小(单位:SP) | -| underline | boolean | 文字是否下划线 | -| underlineColor | @ColorRes int | 文字下划线颜色 | -| underlineWidth | float | 文字下划线线宽 | -| underlineMarginTop | float | 文字下划线向下偏移的距离 | -| deleteLine | boolean | 文字是否删除线 | -| deleteLineColor | @ColorRes int | 文字删除线颜色 | -| deleteLineWidth | float | 文字删除线线宽 | -| backgroundColor | @ColorRes int | 文字区域背景色 | +| 属性 | 参数类型 | 描述 | +|--------------------|:--------------:|:---------------------:| +| textColor | @ColorRes int | 文字资源颜色Id | +| bold | boolean | 文字是否加粗 | +| italic | boolean | 文字是否斜体 | +| strValue | String | 文字String类型值 | +| resValue | @StringRes int | 文字文本资源Id | +| textSize | float | 文字字体大小(单位:SP) | +| underline | boolean | 文字是否下划线 | +| underlineColor | @ColorRes int | 文字下划线颜色 | +| underlineWidth | float | 文字下划线线宽 | +| underlineMarginTop | float | 文字下划线向下偏移的距离 | +| deleteLine | boolean | 文字是否删除线 | +| deleteLineColor | @ColorRes int | 文字删除线颜色 | +| deleteLineWidth | float | 文字删除线线宽 | +| backgroundColor | @ColorRes int | 文字区域背景色 | +| ignorePaintShader | boolean | 文字是否忽略TextView的Shader | +| gradient | Gradient | 文字渐变色配置 | ## FormatImage 参数一览 | 属性 | 参数类型 | 描述 | diff --git a/README.md b/README.md index 6e79c4a..ae9b47f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ ```gradle dependencies { - implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.3' + implementation 'com.github.FlyJingFish:FormatTextViewLib:2.2.4' } ```` ## The third step, instructions for use @@ -222,6 +222,8 @@ ALIGN_CENTER adds an alignment method to the current library to solve the alignm | deleteLineColor | @ColorRes int | Text strikethrough color | | deleteLineWidth | float | Text strikethrough line width | | backgroundColor | @ColorRes int | Text area background color | +| ignorePaintShader | boolean | Whether the text ignores the Shader of the TextView | +| gradient | Gradient | Text Gradient Color Configuration | ## FormatImage parameter list | property | parameter type | description | diff --git a/app/src/main/java/com/flyjingfish/formattextviewdemo/DemoActivity.kt b/app/src/main/java/com/flyjingfish/formattextviewdemo/DemoActivity.kt index 65553b6..2381a1f 100644 --- a/app/src/main/java/com/flyjingfish/formattextviewdemo/DemoActivity.kt +++ b/app/src/main/java/com/flyjingfish/formattextviewdemo/DemoActivity.kt @@ -1,5 +1,6 @@ package com.flyjingfish.formattextviewdemo +import android.graphics.Color import android.graphics.LinearGradient import android.graphics.Shader import android.graphics.drawable.Drawable @@ -30,6 +31,7 @@ class DemoActivity : AppCompatActivity() { underlineMarginTop = 6f underlineWidth = 2f resValue = R.string.User_Agreement + gradient = Gradient(intArrayOf(Color.GREEN,Color.RED),null,Gradient.Orientation.LEFT_TO_RIGHT) }, FormatText().apply { textSize = 22f @@ -41,6 +43,7 @@ class DemoActivity : AppCompatActivity() { underlineMarginTop = 6f underlineWidth = 2f resValue = R.string.Privacy_Policy + gradient = Gradient(intArrayOf(Color.BLUE,Color.RED),null,Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP) } ) text1.setOnFormatClickListener(object :OnFormatClickListener{ @@ -104,6 +107,7 @@ class DemoActivity : AppCompatActivity() { underlineMarginTop = 10f underlineWidth = 3f ignorePaintShader = false + gradient = Gradient(intArrayOf(Color.BLUE,Color.RED),null,Gradient.Orientation.LEFT_BOTTOM_TO_RIGHT_TOP) }, FormatText().apply { textSize = 30f diff --git a/app/src/main/res/layout/activity_demo.xml b/app/src/main/res/layout/activity_demo.xml index 5841b03..d0a3fab 100644 --- a/app/src/main/res/layout/activity_demo.xml +++ b/app/src/main/res/layout/activity_demo.xml @@ -16,7 +16,7 @@ android:text="Hello World!" /> -