TextView 可以做什么?

作者: chendroid | 来源:发表于2020-06-02 20:56 被阅读0次

    我们可以使用 TextView 做些什么呢?
    一般的文本控件可以使用 TextView 来实现,
    那么,还有没有一些其他的场景,可以使用 TextView 实现呢?

    本文想记录一些利用 TextView 实现的场景。

    涉及到以下内容:

    1. 使用 drawableStart|End实现文字 + 图标
    2. 使用 Span 实现「文字+图标混排」效果
    3. 实现带背景的文字效果
    4. 部分点击事件实现
    5. 添加原角背景 + 背景透明度设置

    1. 实现文字 + 图标实现

    想要实现类似这样的效果,文字 + 图标。

    效果图

    其实实现起来特别简单,使用一个 TextView + ImageView 即可。

    但是,如果我们可以使用一个 View 搞定,为什么要使用两个呢?

    TextView 中,有个属性叫做, drawableXXX, 在 xml 中为:

    // 在文字的右边放置图片
    android:drawableEnd="@drawable/ic_action_like"
    // 在文字的左边放置图片
    android:drawableStart="@drawable/ic_action_like"
    // 在文字的上边放置图片
    android:drawableTop="@drawable/ic_action_like"
    // 在文字的下边放置图片
    android:drawableBottom="@drawable/ic_action_like"
    

    所以,当我们想要实现上述的效果时,可以这么使用:

    <TextView
        android:id="@+id/like"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        android:drawableEnd="@drawable/ic_action_like"
        android:drawablePadding="4dp"
        android:gravity="center"
        android:paddingBottom="4dp"
        android:text="123"
        android:textColor="#0084FF"
        android:textSize="12sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    

    上述代码即可实现,文字 + 图标效果 。

    android:drawablePadding 是设置该图标与文字的 padding

    2. 对 TextView 设置 Span 实现「文字+图标混排」效果

    上述的实现,只能把图标固定的放在文字的「前、后、上、下」 这四种效果。
    对于复杂的文字图标混排,就无能为力了。

    那么如何实现「文字+图标混排」效果呢?
    我们可以使用 ImageSpan 实现该效果。

    例如,我们想要这样的效果:


    混排效果

    哈哈哈123,你说不说,那我开始 balabala 了,嘿嘿嘿 中添加爱心图标,
    实现代码如下:

    contentView.text = "哈哈哈123,你说不说,那我开始 balabala 了,嘿嘿嘿"
    val stringBuilder = SpannableString(contentView.text)
    val drawable = getDrawable(R.drawable.ic_action_like)
    val imageSpan = ImageSpan(drawable)
    // 设置 drawable 大小,这里简单处理下
    drawable!!.setBounds(0, 0, 64, 64)
    stringBuilder.setSpan(imageSpan, 10, 12, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    contentView.text = stringBuilder
    

    常见的消息中的小表情,就是利用 ImageSpan 实现的

    小表情的实现,通常是利用特定的字符标志,例如 [笑脸] ,当检测到有类似这种格式 [],会通过一套解析工具,把 [笑脸] 替换成一个 ImageSpan, 从而实现小表情的效果。

    3. 实现带背景的文字效果

    我们想要实现的效果如下:


    部分红色背景

    TextView.getText() 的返回值是 CharSequence
    SpannableStringBuilder 实现了 CharSequence 接口 ,
    表明 TextView 是可以设置 SpannableStringBuilder的,而我们可以利用 SpannableStringBuilder 设置 span 样式,完成很多不一样的样式实现。

    3.1 给部分字体添加背景

    实现代码:

    private fun setupLikeTextView() {
        likeTextView.text = "你说是不是啊?是不是这样的,你猜一下,猜不到吧?在猜一下,哈哈哈哈,就不告诉你"
        val stringBuilder = SpannableStringBuilder(likeTextView.text)
        val backgroundSpan = BackgroundColorSpan(getColor(R.color.colorAccent))
        val start = 3
        val end = content.length
        stringBuilder.setSpan(backgroundSpan, start, end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    
        likeTextView.text = stringBuilder
        }
    

    即可实现,likeTextView.text 从 第 3 个 字符到结尾都会添加一个带颜色的背景。

    主要代码是 stringBuilder 的构建以及 likeTextView.text 的赋值。

    3.2 给部分文字使用不同的颜色

    实现效果如下:


    不同颜色的截图

    hahhaah 这个文案部分, 其中的第 3 ~ 4 个字符使用不同的颜色

    我们可以使用 ForegroundColorSpan 来实现不同颜色的 TextView 文本, 代码如下:

    contentView.text = "hahhaah, 123, 456, 789"
    val foregroundColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.colorAccent))
    val sb = SpannableStringBuilder(contentView.text)
    sb.setSpan(foregroundColorSpan, 3, 5, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE)
    contentView.text = sb
    

    Android 系统中,还有 StrikethroughSpan, UnderlineSpan 等很多可以实现特定样式的 Span 可以供我们使用。

    4. 给 TextView 设置部分文本可点击

    通常在 TextView 中,如果有链接,我们需要实现点击该部分文案时会跳转到该链接的效果。

    代码实现:

    contentView.movementMethod = LinkMovementMethod.getInstance()
    contentView.text = "哈哈哈123,后面是一个链接,可部分点击: https://www.jianshu.com/u/9d38eab6ce45"
    contentView.setLinkTextColor(context.resources.getColor(R.color.blue))
    val contentString = contentView.text
    val start = contentString.indexOfFirst { it == ':' }
    val end = contentView.text.length
    val stringBuilder = SpannableString(contentView.text)
    val clickableSpan = TLClickableSpan()
    stringBuilder.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
    contentView.text = stringBuilder
    

    其中 TLClickableSpan 简单的继承了 ClickableSpan

    class TLClickableSpan : ClickableSpan() {
        
        override fun onClick(widget: View) {
            Log.i("zc_test", "TLClickableSpan is onClick and view is $widget")
        }
    }
    

    实现的效果为:


    可点击的部分文本样式

    点击后的效果, log 提示为 :

    2020-05-29 16:50:07.136 5602-5602/com.chendroid.learning I/zc_test: TLClickableSpan is onClick and view is com.google.android.material.textview.MaterialTextView{5773c57 VFED..CL. ...P.... 72,117-1096,223 #7f0800b7 app:id/item_content}
    

    注意事项

    代码中:contentView.movementMethod = LinkMovementMethod.getInstance() 是必须的, 如果不设置不会响应 ClickableSpan 的点击。
    同时,1. 当 ClickableSpan 生效时,会触发 TextView 的监听事件,消费该事件;

    1. 当点击 TextView 非点击部分时, TextView 也会消费该事件,会导致本来应该传递给 ViewGroup 的事件被 TextView 拦截。

    为了解决 当点击 TextView 非点击部分时, TextView 也会消费该事件, 这个问题,我们可以设置:

    contentView.movementMethod = LinkMovementMethod.getInstance()
    // 不可点击
    contentView.isClickable = false
    // 不可长按
    contentView.isLongClickable = false
    // 不聚焦
    contentView.isFocusable = false
    

    参考链接:https://blog.csdn.net/zhaizu/article/details/51038113

    5. 添加原角背景 + 背景透明度设置

    如果我们想要实现类似这样的效果:

    透明背景
    实现图中自带透明度和圆角的「默认」图标。

    代码如下:

    //xml 中的代码
    <TextView
        android:id="@+id/todo_type"
        android:layout_width="64dp"
        android:layout_height="30dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp"
        android:background="@drawable/bg_blue_8"
        android:gravity="center"
        android:text="默认"
        android:textColor="#0084FF"
        android:textSize="15sp"
        />
    

    其中 @drawable/bg_blue_8 为圆角背景, 源码如下:

    // bg_blue_8.xml
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <corners android:radius="8dp" />
        <solid android:color="#0084FF" />
    </shape>
    

    那么如何实现背景的透明度呢?

    我们不能直接对 TextView 直接设置 TextView.setAlpha(xxx). 因为这样会影响到整个 TextView 的透明度,也会给字体添加上透明度。

    TextView 中有单独对 background 设置的方法,我们需要这样设置:

    type = view.todo_type_1
    type.apply {
        background.alpha = (0.08 * 255).toInt()
        ...
    }
    

    上述代码即可实现我们想要的效果。

    注:该 UI 设计实现方案有很多种,这里只讨论如何只用一个 TextView 实现。
    这样实现的目的:尽可能使界面的渲染高效。避免不必要的内存浪费。

    参考链接:https://www.jianshu.com/p/b5fb51529d06

    6. 总结

    记录了一下,日常在代码中利用 TextView 实现的一些效果,
    内容不难,简单的介绍了代码实现方式。

    我们还可以利用 TextView 实现很多样式的混排效果, 使用 Html 解析或者设置 Span
    可以解决我们遇到的大部分问题。

    这篇文章,如有错误,还请见谅,指出。

    2020.5.30 by chendroid

    相关文章

      网友评论

        本文标题:TextView 可以做什么?

        本文链接:https://www.haomeiwen.com/subject/rpipzhtx.html