技术二三Android应用开发那些事

TextView 可以做什么?

2020-06-02  本文已影响0人  chendroid

我们可以使用 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

上一篇下一篇

猜你喜欢

热点阅读