Merge pull request #199 from TouchInstinct/action_text_view

Add TextView with ClickableSpan substring
This commit is contained in:
Kirill Nayduik 2021-06-25 09:56:35 +03:00 committed by GitHub
commit 9100a23cb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 0 deletions

View File

@ -0,0 +1,3 @@
package ru.touchin.extensions
fun CharSequence.indexesOf(substring: String) = Regex(substring).find(this)?.let { it.range.first to it.range.last + 1 }

View File

@ -1,6 +1,7 @@
apply from: "../android-configs/lib-config.gradle"
dependencies {
implementation project(':kotlin-extensions')
implementation "androidx.core:core"
implementation "androidx.annotation:annotation"

View File

@ -2,9 +2,15 @@ package ru.touchin.roboswag.components.utils.spans
import android.text.SpannableString
import android.text.Spanned
import android.text.TextPaint
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.URLSpan
import android.text.util.Linkify
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.text.HtmlCompat
import ru.touchin.extensions.indexesOf
/**
* Convert text with 'href' tags and raw links to spanned text with clickable URLSpan.
@ -47,3 +53,28 @@ private fun SpannableString.getUrlSpans() = getSpans(0, length, URLSpan::class.j
.map { UrlSpanWithBorders(it, this.getSpanStart(it), this.getSpanEnd(it)) }
private data class UrlSpanWithBorders(val span: URLSpan, val start: Int, val end: Int)
/**
* Find substring inside string (for example in TextView) and fill it with ClickableSpan
*/
fun CharSequence.toClickableSubstringText(
substring: String,
clickAction: () -> Unit,
@ColorInt color: Int? = null,
isUnderlineText: Boolean = false
) = SpannableString(this)
.apply {
indexesOf(substring)?.let { (startSpan, endSpan) ->
setSpan(object : ClickableSpan() {
override fun onClick(widget: View) {
clickAction.invoke()
}
override fun updateDrawState(ds: TextPaint) {
super.updateDrawState(ds)
ds.isUnderlineText = isUnderlineText
if (color != null) ds.color = color
}
}, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}

View File

@ -0,0 +1,44 @@
package ru.touchin.roboswag.views
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.withStyledAttributes
import ru.touchin.roboswag.components.utils.movementmethods.ClickableMovementMethod
import ru.touchin.roboswag.components.utils.spans.toClickableSubstringText
class ActionTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
private var onClickAction: () -> Unit = { }
init {
isClickable = false
isLongClickable = false
highlightColor = Color.TRANSPARENT
movementMethod = ClickableMovementMethod
context.withStyledAttributes(attrs, R.styleable.ActionTextView, defStyleAttr, 0) {
val actionText = getString(R.styleable.ActionTextView_actionText).orEmpty()
val actionColor = getColor(R.styleable.ActionTextView_actionColor, currentTextColor)
val isUnderlineText = getBoolean(R.styleable.ActionTextView_isUnderlineText, false)
text = text.toClickableSubstringText(
substring = actionText,
clickAction = { onClickAction.invoke() },
color = actionColor,
isUnderlineText = isUnderlineText
)
}
}
fun setOnActionClickListener(onClickAction: () -> Unit) {
this.onClickAction = onClickAction
}
}

View File

@ -50,4 +50,10 @@
<attr name="stubText" format="string" />
</declare-styleable>
<declare-styleable name="ActionTextView">
<attr name="actionText" format="string"/>
<attr name="actionColor" format="color"/>
<attr name="isUnderlineText" format="boolean"/>
</declare-styleable>
</resources>