TextView 可以做什么国撵?

我們可以使用 TextView 做些什么呢陵吸?
一般的文本控件可以使用 TextView 來(lái)實(shí)現(xiàn),
那么介牙,還有沒(méi)有一些其他的場(chǎng)景壮虫,可以使用 TextView 實(shí)現(xiàn)呢?

本文想記錄一些利用 TextView 實(shí)現(xiàn)的場(chǎng)景环础。

涉及到以下內(nèi)容:

  1. 使用 drawableStart|End實(shí)現(xiàn)文字 + 圖標(biāo)
  2. 使用 Span 實(shí)現(xiàn)「文字+圖標(biāo)混排」效果
  3. 實(shí)現(xiàn)帶背景的文字效果
  4. 部分點(diǎn)擊事件實(shí)現(xiàn)
  5. 添加原角背景 + 背景透明度設(shè)置

1. 實(shí)現(xiàn)文字 + 圖標(biāo)實(shí)現(xiàn)

想要實(shí)現(xiàn)類(lèi)似這樣的效果囚似,文字 + 圖標(biāo)。

效果圖

其實(shí)實(shí)現(xiàn)起來(lái)特別簡(jiǎn)單线得,使用一個(gè) TextView + ImageView 即可饶唤。

但是,如果我們可以使用一個(gè) View 搞定贯钩,為什么要使用兩個(gè)呢搬素?

TextView 中,有個(gè)屬性叫做魏保, 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"

所以,當(dāng)我們想要實(shí)現(xiàn)上述的效果時(shí)谓罗,可以這么使用:

<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" />

上述代碼即可實(shí)現(xiàn)粱哼,文字 + 圖標(biāo)效果 。

android:drawablePadding 是設(shè)置該圖標(biāo)與文字的 padding

2. 對(duì) TextView 設(shè)置 Span 實(shí)現(xiàn)「文字+圖標(biāo)混排」效果

上述的實(shí)現(xiàn)檩咱,只能把圖標(biāo)固定的放在文字的「前揭措、后胯舷、上、下」 這四種效果绊含。
對(duì)于復(fù)雜的文字圖標(biāo)混排桑嘶,就無(wú)能為力了。

那么如何實(shí)現(xiàn)「文字+圖標(biāo)混排」效果呢躬充?
我們可以使用 ImageSpan 實(shí)現(xiàn)該效果逃顶。

例如,我們想要這樣的效果:


混排效果

哈哈哈123充甚,你說(shuō)不說(shuō)以政,那我開(kāi)始 balabala 了,嘿嘿嘿 中添加愛(ài)心圖標(biāo)伴找,
實(shí)現(xiàn)代碼如下:

contentView.text = "哈哈哈123盈蛮,你說(shuō)不說(shuō),那我開(kāi)始 balabala 了技矮,嘿嘿嘿"
val stringBuilder = SpannableString(contentView.text)
val drawable = getDrawable(R.drawable.ic_action_like)
val imageSpan = ImageSpan(drawable)
// 設(shè)置 drawable 大小抖誉,這里簡(jiǎn)單處理下
drawable!!.setBounds(0, 0, 64, 64)
stringBuilder.setSpan(imageSpan, 10, 12, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
contentView.text = stringBuilder

常見(jiàn)的消息中的小表情,就是利用 ImageSpan 實(shí)現(xiàn)的

小表情的實(shí)現(xiàn)衰倦,通常是利用特定的字符標(biāo)志寸五,例如 [笑臉] ,當(dāng)檢測(cè)到有類(lèi)似這種格式 []耿币,會(huì)通過(guò)一套解析工具梳杏,把 [笑臉] 替換成一個(gè) ImageSpan, 從而實(shí)現(xiàn)小表情的效果淹接。

3. 實(shí)現(xiàn)帶背景的文字效果

我們想要實(shí)現(xiàn)的效果如下:


部分紅色背景

TextView.getText() 的返回值是 CharSequence
SpannableStringBuilder 實(shí)現(xiàn)了 CharSequence 接口 ,
表明 TextView 是可以設(shè)置 SpannableStringBuilder的十性,而我們可以利用 SpannableStringBuilder 設(shè)置 span 樣式,完成很多不一樣的樣式實(shí)現(xiàn)塑悼。

3.1 給部分字體添加背景

實(shí)現(xiàn)代碼:

private fun setupLikeTextView() {
    likeTextView.text = "你說(shuō)是不是熬⑹省?是不是這樣的厢蒜,你猜一下霞势,猜不到吧?在猜一下斑鸦,哈哈哈哈愕贡,就不告訴你"
    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
    }

即可實(shí)現(xiàn),likeTextView.text 從 第 3 個(gè) 字符到結(jié)尾都會(huì)添加一個(gè)帶顏色的背景巷屿。

主要代碼是 stringBuilder 的構(gòu)建以及 likeTextView.text 的賦值固以。

3.2 給部分文字使用不同的顏色

實(shí)現(xiàn)效果如下:


不同顏色的截圖

hahhaah 這個(gè)文案部分, 其中的第 3 ~ 4 個(gè)字符使用不同的顏色

我們可以使用 ForegroundColorSpan 來(lái)實(shí)現(xiàn)不同顏色的 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 系統(tǒng)中,還有 StrikethroughSpan, UnderlineSpan 等很多可以實(shí)現(xiàn)特定樣式的 Span 可以供我們使用憨琳。

4. 給 TextView 設(shè)置部分文本可點(diǎn)擊

通常在 TextView 中诫钓,如果有鏈接,我們需要實(shí)現(xiàn)點(diǎn)擊該部分文案時(shí)會(huì)跳轉(zhuǎn)到該鏈接的效果篙螟。

代碼實(shí)現(xiàn):

contentView.movementMethod = LinkMovementMethod.getInstance()
contentView.text = "哈哈哈123菌湃,后面是一個(gè)鏈接,可部分點(diǎn)擊: http://www.reibang.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 簡(jiǎn)單的繼承了 ClickableSpan

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

實(shí)現(xiàn)的效果為:


可點(diǎn)擊的部分文本樣式

點(diǎn)擊后的效果遍略, 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}

注意事項(xiàng)

代碼中:contentView.movementMethod = LinkMovementMethod.getInstance() 是必須的惧所, 如果不設(shè)置不會(huì)響應(yīng) ClickableSpan 的點(diǎn)擊。
同時(shí)墅冷,1. 當(dāng) ClickableSpan 生效時(shí),會(huì)觸發(fā) TextView 的監(jiān)聽(tīng)事件或油,消費(fèi)該事件寞忿;

  1. 當(dāng)點(diǎn)擊 TextView 非點(diǎn)擊部分時(shí), TextView 也會(huì)消費(fèi)該事件顶岸,會(huì)導(dǎo)致本來(lái)應(yīng)該傳遞給 ViewGroup 的事件被 TextView 攔截腔彰。

為了解決 當(dāng)點(diǎn)擊 TextView 非點(diǎn)擊部分時(shí), TextView 也會(huì)消費(fèi)該事件辖佣, 這個(gè)問(wèn)題霹抛,我們可以設(shè)置:

contentView.movementMethod = LinkMovementMethod.getInstance()
// 不可點(diǎn)擊
contentView.isClickable = false
// 不可長(zhǎng)按
contentView.isLongClickable = false
// 不聚焦
contentView.isFocusable = false

參考鏈接:https://blog.csdn.net/zhaizu/article/details/51038113

5. 添加原角背景 + 背景透明度設(shè)置

如果我們想要實(shí)現(xiàn)類(lèi)似這樣的效果:

透明背景

實(shí)現(xiàn)圖中自帶透明度和圓角的「默認(rèn)」圖標(biāo)。

代碼如下:

//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="默認(rèn)"
    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>

那么如何實(shí)現(xiàn)背景的透明度呢卷谈?

我們不能直接對(duì) TextView 直接設(shè)置 TextView.setAlpha(xxx). 因?yàn)檫@樣會(huì)影響到整個(gè) TextView 的透明度杯拐,也會(huì)給字體添加上透明度。

TextView 中有單獨(dú)對(duì) background 設(shè)置的方法世蔗,我們需要這樣設(shè)置:

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

上述代碼即可實(shí)現(xiàn)我們想要的效果端逼。

注:該 UI 設(shè)計(jì)實(shí)現(xiàn)方案有很多種,這里只討論如何只用一個(gè) TextView 實(shí)現(xiàn)污淋。
這樣實(shí)現(xiàn)的目的:盡可能使界面的渲染高效顶滩。避免不必要的內(nèi)存浪費(fèi)。

參考鏈接:http://www.reibang.com/p/b5fb51529d06

6. 總結(jié)

記錄了一下寸爆,日常在代碼中利用 TextView 實(shí)現(xiàn)的一些效果礁鲁,
內(nèi)容不難,簡(jiǎn)單的介紹了代碼實(shí)現(xiàn)方式赁豆。

我們還可以利用 TextView 實(shí)現(xiàn)很多樣式的混排效果仅醇, 使用 Html 解析或者設(shè)置 Span
可以解決我們遇到的大部分問(wèn)題。

這篇文章魔种,如有錯(cuò)誤着憨,還請(qǐng)見(jiàn)諒,指出务嫡。

2020.5.30 by chendroid

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甲抖,一起剝皮案震驚了整個(gè)濱河市漆改,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌准谚,老刑警劉巖挫剑,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異柱衔,居然都是意外死亡樊破,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)唆铐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哲戚,“玉大人,你說(shuō)我怎么就攤上這事艾岂∷成伲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵王浴,是天一觀的道長(zhǎng)脆炎。 經(jīng)常有香客問(wèn)我,道長(zhǎng)氓辣,這世上最難降的妖魔是什么秒裕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮钞啸,結(jié)果婚禮上几蜻,老公的妹妹穿的比我還像新娘。我一直安慰自己体斩,他們只是感情好入蛆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著硕勿,像睡著了一般哨毁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上源武,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天扼褪,我揣著相機(jī)與錄音,去河邊找鬼粱栖。 笑死话浇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闹究。 我是一名探鬼主播幔崖,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赏寇?” 一聲冷哼從身側(cè)響起吉嫩,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗅定,沒(méi)想到半個(gè)月后自娩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渠退,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年忙迁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碎乃。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姊扔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梅誓,到底是詐尸還是另有隱情恰梢,我是刑警寧澤程奠,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布痪伦,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏愧怜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一妈拌、第九天 我趴在偏房一處隱蔽的房頂上張望拥坛。 院中可真熱鬧,春花似錦尘分、人聲如沸猜惋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)著摔。三九已至,卻和暖如春定续,著一層夾襖步出監(jiān)牢的瞬間谍咆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工私股, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摹察,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓倡鲸,卻偏偏與公主長(zhǎng)得像供嚎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354