经常使用 SpannableString ,所以写了个扩展函数

经常使用 SpannableString ,所以写了个扩展函数
类名: SpannableStringExt.kt
package xxx

import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.text.Spannable
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.text.style.AbsoluteSizeSpan
import android.text.style.BackgroundColorSpan
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.text.style.SubscriptSpan
import android.text.style.SuperscriptSpan
import android.text.style.URLSpan
import android.text.style.UnderlineSpan
import android.view.View
import android.widget.TextView
import com.geaosu.libsExtensions.span.ClickableSpanWithOutUnderLine


/**
 * SpannableString 的扩展函数
 */


/* ====== 用法 ======
    val content = " 您在使用我们的产品前,请认真阅读《用户协议》及《隐私政策》,您同意并接受后方可开始使用我们的产品。请在百度上联系我们10086"
    val targetOne = "《用户协议》"
    val targetTwo = "《隐私政策》"
    SpannableString(content)
        .addImage(resources.getDrawable(R.drawable.ic_launcher_background), DpUtils.dp2px(mActivity, 22f), DpUtils.dp2px(mActivity, 22f), 0)
        .addOnClickListenerWithOutUnderline(targetOne, { mOnDialogStateChangedListener?.onBtnUserXieYiClick(Constants.XIE_YI_TYPE_1_TITLE, Constants.XIE_YI_TYPE_1) })
        .addOnClickListenerWithOutUnderline(targetTwo, { mOnDialogStateChangedListener?.onBtnUrlClick(Constants.URL_YIN_SI_XIE_YI_TITLE, Constants.URL_YIN_SI_XIE_YI) })
        .addColor(targetOne, mActivity.resources.getColor(R.color.color_main))
        .addColor(targetTwo, mActivity.resources.getColor(R.color.color_main))
        .addBold(targetOne)
        .addBold(targetTwo)
        .addPhoneClick("10086") // 点击 10086,拨打 10086
        .addPhoneClick("联系我们", "10086")// 点击 联系我们,拨打 10086
        .addUrlClick("https://www.baidu.com/") // 点击 https://www.baidu.com/,用系统浏览器打开 https://www.baidu.com/
        .addUrlClick("百度", "https://www.baidu.com/")// 点击百度,用系统浏览器打开 https://www.baidu.com/
        .into(id_content)

 */



/**
 * 加颜色
 * @param target 目标字符串
 * @param color 颜色
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addColor(target: String, color: Int, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(ForegroundColorSpan(color), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加文字背景颜色
 * @param target 目标字符串
 * @param color 颜色
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addBgColor(target: String, color: Int, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(BackgroundColorSpan(color), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加粗
 * @param target 目标字符串
 * @param flags 标记
 * @return SpannableString
 */
fun SpannableString.addBold(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(StyleSpan(Typeface.BOLD), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加斜体
 * @param target 目标字符串
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addItalics(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(StyleSpan(Typeface.ITALIC), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加下划线
 * @param target 目标字符串
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addUnderline(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(UnderlineSpan(), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加删除线
 * @param target 目标字符串
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addDeleteLine(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(StrikethroughSpan(), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 修改指定文字的文字大小
 * @param target 目标字符串
 * @param size 文字大小
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addSize(target: String, size: Int, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(AbsoluteSizeSpan(size), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加图片
 * (注意:会替换掉一个字符,所以,最好在对应的位置上增加一个空格,用于被图片替换掉)
 * @param drawable 图片
 * @param drawableWith 图片宽度
 * @param drawableHeight 图片高度
 * @param startIndex 开始位置
 * @param endIndex 结束位置
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addImage(drawable: Drawable, drawableWith: Int, drawableHeight: Int, startIndex: Int, flags: Int = ImageSpan.ALIGN_CENTER): SpannableString {
    drawable.setBounds(0, 0, drawableWith, drawableHeight)
    this.setSpan(ImageSpan(drawable), startIndex, startIndex + 1, flags)
    return this
}

/**
 * 加图片,在字符串的最前面加图片
 * (注意:会替换掉一个字符,所以第一个字符的位置会发生变化,最好在第一个位置增加一个空格,用于被图片替换掉)
 * @param drawable 图片
 * @param drawableWith 图片宽度
 * @param drawableHeight 图片高度
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addImageOnStart(drawable: Drawable, drawableWith: Int, drawableHeight: Int, flags: Int = ImageSpan.ALIGN_CENTER): SpannableString {
    drawable.setBounds(0, 0, drawableWith, drawableHeight)
    this.setSpan(ImageSpan(drawable), 0, 1, flags)
    return this
}

/**
 * 加上标
 * @param target 目标字符串
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addSup(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(SuperscriptSpan(), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加下标
 * @param target 目标字符串
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addSizeSub(target: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(SubscriptSpan(), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加点击事件,文字带下划线
 * (注意:需要设置setMovementMethod方法,可以直接调用TextView 的扩展函数中的 setSpannableStringClickEnable函数)
 * @param target 目标字符串
 * @param listener 点击事件
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addOnClickListener(target: String, listener: View.OnClickListener, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(object : ClickableSpan() {
            override fun onClick(widget: View) {
                listener.onClick(widget)
            }
        }, startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加点击事件,文字不带下划线
 * (注意:需要设置setMovementMethod方法,可以直接调用TextView 的扩展函数中的 setSpannableStringClickEnable函数)
 * @param target 目标字符串
 * @param listener 点击事件
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addOnClickListenerWithOutUnderline(target: String, listener: View.OnClickListener, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(target)) {
        val startIndex: Int = this.indexOf(target)
        val endIndex = startIndex + target.length
        this.setSpan(object : ClickableSpanWithOutUnderLine() {
            override fun onClick(widget: View) {
                listener.onClick(widget)
            }
        }, startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加超链接 - 打电话
 * @param phoneNo 电话号码
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addPhoneClick(phoneNo: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(phoneNo)) {
        val startIndex: Int = this.indexOf(phoneNo)
        val endIndex = startIndex + phoneNo.length
        this.setSpan(URLSpan("tel:$phoneNo"), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加超链接 - 打电话
 * @param phoneNo 电话号码
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addPhoneClick(title: String, phoneNo: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(title)) {
        val startIndex: Int = this.indexOf(title)
        val endIndex = startIndex + title.length
        this.setSpan(URLSpan("tel:$phoneNo"), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加超链接 - 打开网页
 * @param url 网页地址
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addUrlClick(url: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(url)) {
        val startIndex: Int = this.indexOf(url)
        val endIndex = startIndex + url.length
        this.setSpan(URLSpan(url), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 加超链接 - 打开网页
 * @param url 网页地址
 * @param flags 标志
 * @return SpannableString
 */
fun SpannableString.addUrlClick(title: String, url: String, flags: Int = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE): SpannableString {
    if (containsSubstring(title)) {
        val startIndex: Int = this.indexOf(title)
        val endIndex = startIndex + title.length
        this.setSpan(URLSpan(url), startIndex, endIndex, flags)
    }
    return this
}

/**
 * 判断SpannableString中是否包含某个字符串
 * @param target 目标字符串
 * @return Boolean true包含,false不包含
 */
fun SpannableString.containsSubstring(target: String): Boolean {
    return this.toString().contains(target)
}

/**
 * 当TextView设置了SpannableString后,启用SpannableString的点击事件
 * @param textView TextView
 * @return SpannableString
 */
fun SpannableString.setSpannableStringClickEnable(textView: TextView): SpannableString {
    textView.movementMethod = LinkMovementMethod.getInstance()
    return this
}

/**
 * 设置TextView的文本
 * @param view TextView
 */
fun SpannableString.into(textView: TextView) {
    textView.movementMethod = LinkMovementMethod.getInstance()
    textView.text = this
}
默认的点击事件文字带下划线,这里提供一个不带下划线的 ClickableSpanWithOutUnderLine
package com.geaosu.libsExtensions.span;

import android.text.TextPaint;
import android.text.style.ClickableSpan;

/**
 * 重写ClickableSpan,去掉文字的下划线
 */
public abstract class ClickableSpanWithOutUnderLine extends ClickableSpan {
    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false); // 是否增加下划线:true增加,false不增加   (能被点击的文字下面增加下划线)
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值