Android圖文混排實現(xiàn)方式詳解

在使用TextView的時候乡翅,我們經(jīng)常需要在TextView中進(jìn)行圖文混排鳞疲,比如在QQ中聊天的消息中的表情,底部tab圖標(biāo)等峦朗。

一建丧、場景

image

二、實現(xiàn)方式

Android官方對TextView的圖文混排提供了支持波势,我們可以從以下三種方式實現(xiàn)TextView的圖文混排:

1.在TextView中使用Compound Drawable屬性翎朱;
2.在TextView中使用Spannable多樣式顯示;
3.在TextView中顯示HTML文本尺铣。

三拴曲、drawable屬性

在TextView中使用Compound Drawable屬性可以在文字的上下左右放置drawable,效果如下:

image

一共有兩種方式可以實現(xiàn):XML布局設(shè)置和Java代碼設(shè)置凛忿。

1. xml布局

 <TextView
        android:gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查看新的內(nèi)容"
        android:textSize="18sp"
        android:drawablePadding="10dp"
        android:drawableLeft="@drawable/arrow"/>

android:drawableLeft 在文字左邊設(shè)置圖片
android:drawableTop 在文字上邊設(shè)置圖片
android:drawableRight 在文字右邊設(shè)置圖片
android:drawableBottom 在文字下邊設(shè)置圖片
android:drawableStart API 17后生效澈灼,LTR時在左邊,RTL時在右邊
android:drawableEnd API 17后生效店溢,LTR時在右邊叁熔,RTL時在左邊
android:drawablePadding 圖片和文字的間距

2. java代碼

        textView = (TextView) findViewById(R.id.textView);
        Drawable drawable = getResources().getDrawable(R.drawable.see);
        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
        textView.setCompoundDrawables(null,null,null,drawable);
        textView.setCompoundDrawablePadding(10);

注意:必須setBounds()測量圖片邊界,否則不顯示床牧。

setCompoundDrawables 設(shè)置上下左右位置的圖片
setCompoundDrawablesRelative 設(shè)置四周的圖片荣回,其中兩邊對應(yīng)xml中的start,end
setCompoundDrawablesWithIntrinsicBounds 設(shè)置上下左右位置的圖片,圖片有默認(rèn)的邊界
setCompoundDrawablesRelativeWithIntrinsicBounds 設(shè)置四周的圖片戈咳,圖片有默認(rèn)的邊界
setCompoundDrawablePadding 設(shè)置圖片與文字之間的間距

3.缺陷

當(dāng)TextView設(shè)置成固定大小時心软,由于文字距離邊界的距離過大,會導(dǎo)致文字與圖片之間設(shè)置的間距無效著蛙,如下圖删铃。

image

解決方案:

①設(shè)置TextView的內(nèi)填充

通過設(shè)置paddingLeft、paddingRight踏堡、paddingTop猎唁、paddingBottom來縮寫這個間距

②自定義TextView重新布局

a.先自定義屬性iconPadding來設(shè)置間距,并提供方法給外部調(diào)用顷蟆。

b.重寫setCompoundDrawablesWithIntrinsicBounds()方法來獲取我們設(shè)置的drawable寬高胖秒。

c.最后重寫onLayout方法缎患。

可以先參考:Android技巧之drawablePadding的那些事,該篇文章只解決了左右失效的問題。后期會整理個解決圖文混排的工具庫阎肝,里面會有具體方案。

四肮街、Spannable使用

1.簡介

setText(CharSequence text)中接收的是CharSequence风题。而SpannableString和SpannableStringBuilder是其實現(xiàn)類,是可以直接賦值的嫉父。并且兩者的setSpan()方法可以設(shè)置一些格式對象(例如字體大小沛硅、下劃線、替換為圖片等)绕辖,這就可以實現(xiàn)富文本了摇肌。

Spannable實現(xiàn)子類:SpannableString,SpannableStringBuilder(可變仪际,類似于StringBuilder)围小。

Spannable中定義了抽象方法:setSpan(Object what, int start, int end, int flags)和removeSpan(Object what)。這兩個方法實現(xiàn)了對字符串的靈活編輯树碱。

其中setSpan()方法包含如下參數(shù):

參數(shù) 參數(shù)說明
what span樣式
start 樣式開始的索引
end 樣式結(jié)束的索引
flags 樣式作用的范圍

flags常用的有四種

SPAN_INCLUSIVE_INCLUSIVE 前后都包括肯适,在指定范圍前后插入新字符,都會應(yīng)用新樣式
SPAN_EXCLUSIVE_EXCLUSIVE 前后都不包括成榜,在指定范圍前后插入新字符框舔,兩端樣式無變化
SPAN_INCLUSIVE_EXCLUSIVE 前面包括,后面不包括
SPAN_EXCLUSIVE_INCLUSIVE 后面包括赎婚,前面不包括

通常在insert方式才生效刘绣,平時不生效,具體看:Explain the meaning of Span flags like SPAN_EXCLUSIVE_EXCLUSIVE挣输。

2.常用span類

常用類 說明
BackgroundColorSpan 背景色樣式纬凤,顯然可以用來設(shè)定文本的背景色
ForegroundColorSpan 字體顏色樣式,用于改變字體顏色
StyleSpan 主要由正常歧焦、粗體移斩、斜體和同時加粗傾斜四種樣式
TypefaceSpan 設(shè)置不同的字體
ImageSpan 圖片樣式,主要用于在文本中插入圖片
URLSpan 可以打開一個鏈接
UnderlineSpan 下劃線樣式
StrikethroughSpan 刪除線樣式

3.使用方式

        SpannableString span3 = new SpannableString("我如果愛你");
        ImageSpan image = new ImageSpan(this,R.drawable.collect, DynamicDrawableSpan.ALIGN_BOTTOM);
        span3.setSpan(image,3,4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv3.setText(span3);

其中ImageSpan默認(rèn)對其方式有兩種:ALIGN_BOTTOM及ALIGN_BASELINE绢馍。很可惜我們平常用的居中對其的方式?jīng)]有向瓷,不過可以通過自定義實現(xiàn),后續(xù)會在開源出來舰涌。

4.效果

image

五猖任、HTML顯示

一般顯示HTML內(nèi)容有兩種方式:

  • 使用 Android 提供的 WebView 控件。
  • 通過將 HTML 內(nèi)容轉(zhuǎn)化為 Spanned 格式在 TextView 中進(jìn)行顯示瓷耙。

現(xiàn)在大多數(shù)都用WebView的方式朱躺。但是并不是所有的場景下都適合使用 WebView 來顯示 HTML 內(nèi)容刁赖,例如,如果應(yīng)用要顯示的內(nèi)容只是一部分 HTML 片段长搀,就可以利用 TextView 來進(jìn)行顯示宇弛,并且效率較高。

由于這種方式不太常用源请,就不深入介紹枪芒,里面可以實現(xiàn)的效果還是很好的。

1.簡介

Android 中的 TextView 組件常用于顯示文本內(nèi)容谁尸,其實它也可以顯示 HTML 的內(nèi)容舅踪。

簡單來講,這就需要先把 HTML 的內(nèi)容以字符串的形式獲取后良蛮,經(jīng)過 android.text.Html.fromHtml()轉(zhuǎn)化成 Spanned 的格式抽碌,然后將其傳遞到 TextView 的 setText()方法中,這樣就可以在 TextView 中顯示 HTML 頁面的內(nèi)容了决瞳。

需要注意的是货徙,并不是所有的 HTML 標(biāo)簽在 TextView 中都是支持的,且官方文檔并沒有明確的說明支持 HTML 標(biāo)簽列表瞒斩,通過查看 Android 源代碼破婆,可以得到簡單的支持列表。


,< p>,< div align=>,< strong>, <b>, <em>, <cite>, <dfn>, <i>, <big>, <small>, <font size=>, <font color=>, <blockquote>, <tt>, <a href=>,
<u>, , , <h1>,<h2>,<h3>,<h4>,<h5>,<h6>, <img src=>, <strike>

下面的示例來介紹如何在 TextView 中顯示一段 HTML 內(nèi)容胸囱,要顯示的這段 HTML 內(nèi)容即包含超鏈接內(nèi)容祷舀,也包含有圖片。

2.使用

fromHtml方法

fromHtml(String source, ImageGetter imageGetter,TagHandler tagHandler)

  • source烹笔,就是包含 HTML 內(nèi)容的字符串裳扯。Html.ImageGetter 和 Html.TagHandler 是兩個接口,提供給開發(fā)者繼承使用谤职。
  • imageGetter饰豺, 如果要顯示圖片是需要被繼承的,重寫 getDrawable(String source)方法允蜈,用于獲取 HTML 里面的圖片來顯示在 TextView 中冤吨。
  • tagHandler,其作用是把 HTML 帶標(biāo)記的文本內(nèi)容字符串轉(zhuǎn)化成可以顯示效果的的 Spanned 字符串 饶套。由于并非所有的 HTML 標(biāo)簽都可以轉(zhuǎn)化漩蟆,所以在使用時,用戶需要自己添加一些必要的標(biāo)簽和處理方法時才會繼承使用的妓蛮。

繼承ImageGetter

繼承于 ImageGetter怠李,重寫 getDrawable (String source) 方法。通過異步操作,讀取本地/網(wǎng)絡(luò)資源捺癞,獲得drawable對象夷蚊。

繼承TagHandler

繼承于 TagHandler,重寫了 handleTag()方法髓介。為了支持更多的標(biāo)簽惕鼓,例如為了支持<ul><ol><dd>和<li>標(biāo)簽,這四個標(biāo)簽是在 formHtml()方法中本身是不支持唐础。

如果開發(fā)者認(rèn)為安卓 TagHandler 提供的默認(rèn)標(biāo)簽解析已經(jīng)夠用彻犁,直接在 fromHtml()方法中第三個參數(shù)的地方填寫 null 既可。

最后,通過 formHtml()方法將 HTML 內(nèi)容轉(zhuǎn)化為可供顯示的 SpannableString仲智,將 SpannableString 通過 setText 方法放入 TextView 中肴焊,就可以顯示圖文并茂的內(nèi)容了娶眷。

用戶交互

formHtml()方法已經(jīng)將 HTML 內(nèi)容中的超鏈接和圖片轉(zhuǎn)義成為 UrlSpan 和 ImageSpan烁落,進(jìn)而在 TextView 中完成顯示。但是此時是沒有任何用戶交互的,用戶只能看到 HTML 的內(nèi)容熊痴,下面介紹如何添加用戶交互功能诊笤。

要完成用戶交互鄙煤,這里我們需要在 TextView 中還需要調(diào)用textView.setMovementMethod()方法凉馆。

Android 提供了 LinkMovementMethod 類以實現(xiàn)了對于文本內(nèi)容中超鏈接的遍歷,并且支持對于超鏈接的點擊事件。

所以只要在添加下面一行代碼京革,就可以使點擊 UrlSpan 能夠觸發(fā)打開鏈接的功能。

textView.setMovementMethod(LinkMovementMethod.getInstance())

如果想要更多的用戶交互效果来惧,可以自定義LinkMovementMethod 類,重寫onTouchEvent方法來實現(xiàn)葛虐。

3.效果

image

點擊圖片,跳轉(zhuǎn)到圖片詳情頁万栅。

關(guān)于HTML顯示這部分扰她,沒做具體實現(xiàn)。具體可以看:靈活高效的在 Android Native App 開發(fā)中顯示 HTML 內(nèi)容,里面有具體源碼可以下載窖壕,HTML部分內(nèi)容也是參考該篇文章完成的廉涕。
開源庫:html-textview

轉(zhuǎn)自:http://www.reibang.com/p/6843f332c8df

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市艇拍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宠纯,老刑警劉巖卸夕,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異婆瓜,居然都是意外死亡快集,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門廉白,熙熙樓的掌柜王于貴愁眉苦臉地迎上來个初,“玉大人,你說我怎么就攤上這事猴蹂≡耗纾” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵磅轻,是天一觀的道長珍逸。 經(jīng)常有香客問我,道長聋溜,這世上最難降的妖魔是什么谆膳? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮撮躁,結(jié)果婚禮上漱病,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好杨帽,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布漓穿。 她就那樣靜靜地躺著,像睡著了一般睦尽。 火紅的嫁衣襯著肌膚如雪器净。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天当凡,我揣著相機(jī)與錄音山害,去河邊找鬼。 笑死沿量,一個胖子當(dāng)著我的面吹牛浪慌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朴则,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼权纤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了乌妒?” 一聲冷哼從身側(cè)響起汹想,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撤蚊,沒想到半個月后古掏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡侦啸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年槽唾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片光涂。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡庞萍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忘闻,到底是詐尸還是另有隱情钝计,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布齐佳,位于F島的核電站葵蒂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏重虑。R本人自食惡果不足惜践付,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缺厉。 院中可真熱鬧永高,春花似錦隧土、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饲宛,卻和暖如春皆愉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艇抠。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工幕庐, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人家淤。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓异剥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親絮重。 傳聞我的和親對象是個殘疾皇子冤寿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容