整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          TextView實(shí)現(xiàn)Android圖文混排顯示HTML內(nèi)容

          ndroid 中的 TextView 組件常用于顯示文本內(nèi)容,其實(shí)它也可以顯示 HTML 的內(nèi)容。簡(jiǎn)單來講,這就需要先把 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 源代碼,可以得到簡(jiǎn)單的支持列表。

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

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

          顯示的過程中最主要的過程就是調(diào)用 Android.text.Html 類提供的 fromHtml()方法,將一段 HTML 內(nèi)容轉(zhuǎn)化為 Spanned 對(duì)象。

          Android.text.Html 類提供的 fromHtml()方法使用如下清單 4
          fromHtml()方法定義

          public static Spanned fromHtml(String source, ImageGetter imageGetter,
              TagHandler tagHandler) {
                  ……
          HtmlToSpannedConverter converter =
          new HtmlToSpannedConverter(source, imageGetter, tagHandler,  parser);
          return converter.convert();
          }
          1234567

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

          在本例中使用 fromHtml()方法之前,要準(zhǔn)備好該方法要用的三個(gè)參數(shù)內(nèi)容,首先將 HTML 字符串內(nèi)容準(zhǔn)備好,在項(xiàng)目中需要?jiǎng)?chuàng)建兩個(gè)類 MImageGetter 和 MTagHandler 分別繼承于 ImageGetter 和 TagHandler,分別用戶圖片的獲取,和特殊標(biāo)簽的支持。
          MImageGetter

          繼承于 ImageGetter,重寫 getDrawable (String source) 方法中從 assets 路徑下取出的圖片流(這里當(dāng)然也可以通過網(wǎng)絡(luò)操作來完成圖片流的獲取),最后獲得可供顯示的圖片對(duì)象,例如 Drawable 對(duì)像。由于 Android 設(shè)備的異構(gòu)性,為了有更好的顯示效果,通常需要獲取屏幕大小,然后調(diào)用 drawable.setBounds () 還可以重新設(shè)置圖片的大小, 最后返回合適大小的圖片 Drawable 對(duì)象。 由此 Spanned 中的 ImageSpan 就獲得了圖像被顯示在 TextView 中對(duì)應(yīng)位置了。

          TypedValue typedValue = new TypedValue();
          typedValue.density = TypedValue.DENSITY_DEFAULT;
          drawable = Drawable.createFromResourceStream(null, typedValue, is, "src");
          DisplayMetrics dm = c.getResources().getDisplayMetrics();  
          int dwidth = dm.widthPixels-10;//padding left + padding right
          float dheight = (float)drawable.getIntrinsicHeight()*(float)dwidth/(float)drawable.getIntrinsicWidth();
          int dh = (int)(dheight+0.5);
          int wid = dwidth;
          int hei = dh;
          drawable.setBounds(0, 0, wid, hei);DisplayMetrics dm = c.getResources().getDisplayMetrics();
          12345678910

          MTagHandler

          繼承于 TagHandler,重寫了 handleTag()方法,為的是支持部分標(biāo)簽,這四個(gè)標(biāo)簽是在 formHtml()方法中本身是不支持。如果開發(fā)者認(rèn)為安卓 TagHandler 提供的默認(rèn)標(biāo)簽解析已經(jīng)夠用,直接在 fromHtml()方法中第三個(gè)參數(shù)的地方填寫 null 既可。
          重寫 handleTag()方法

          public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
          if (tag.equals("ul") || tag.equals("ol") || tag.equals("dd")) {
              if (opening) {
              mListParents.add(tag);
              } else mListParents.remove(tag);
          } else if (tag.equals("li") && !opening) {
               handleListTag(output);
          }
          }
          private void handleListTag(Editable output) {
          ……
           }
          123456789101112

          最后,在完成了 MImageGetter、MTagHandler 以后,就可以通過 formHtml()方法將 HTML 內(nèi)容轉(zhuǎn)化為可供顯示的 SpannableString,將 SpannableString 通過 setText 方法放入 TextView 中,就可以顯示圖文并茂的內(nèi)容了。

          progressBar.setVisibility(View.GONE);
          text.setText(Html.fromHtml(htmlCont, new MImageGetter(text,MainActivity.this), new MTagHandler()));
          text.setVisibility(View.VISIBLE);
          123

          MImageGetter、MTagHandler 如下:

          者博客

          http://www.jianshu.com/u/0fa6f5d09040

          文章目錄

          • 前言

          • 場(chǎng)景

          • 實(shí)現(xiàn)方式

          • drawable屬性

          • Spannable使用

          • HTML顯示

          • 總結(jié)


          0

          前言

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

          1

          場(chǎng)景

          2

          實(shí)現(xiàn)方式

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

          1.在TextView中使用Compound Drawable屬性;

          2.在TextView中使用Spannable多樣式顯示;

          3.在TextView中顯示HTML文本。

          3

          drawable屬性

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

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

          1. xml布局

          2. java代碼

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

          3.缺陷

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

          解決方案:

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

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

          ②自定義TextView重新布局

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

          b.重寫setCompoundDrawablesWithIntrinsicBounds方法來獲取我們?cè)O(shè)置的drawable寬高。

          c.最后重寫onLayout方法。

          可以先參考:Android技巧之drawablePadding的那些事(https://yuxingxin.com/2015/11/05/DrawablePadding/),該篇文章只解決了左右失效的問題。后期會(huì)整理個(gè)解決圖文混排的工具庫,里面會(huì)有具體方案。

          4

          Spannable使用

          1.簡(jiǎn)介

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

          Spannable實(shí)現(xiàn)子類:SpannableString,SpannableStringBuilder(可變,類似于StringBuilder)。

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

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

          flags常用的有四種

          通常在insert方式才生效,平時(shí)不生效,具體看:Explain the meaning of Span flags like SPAN_EXCLUSIVE_EXCLUSIVE。(https://stackoverflow.com/questions/9879233/explain-the-meaning-of-span-flags-like-span-exclusive-exclusive)

          2.常用span類

          3.使用方式

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

          4.效果

          5

          HTML顯示

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

          • 使用 Android 提供的 WebView 控件。


          • 通過將 HTML 內(nèi)容轉(zhuǎn)化為 Spanned 格式在 TextView 中進(jìn)行顯示。

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

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

          1.簡(jiǎn)介

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

          簡(jiǎn)單來講,這就需要先把 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 源代碼,可以得到簡(jiǎn)單的支持列表。

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

          2.使用

          fromHtml方法

          source,就是包含 HTML 內(nèi)容的字符串。Html.ImageGetter 和 Html.TagHandler 是兩個(gè)接口,提供給開發(fā)者繼承使用。

          imageGetter, 如果要顯示圖片是需要被繼承的,重寫 getDrawable(String source)方法,用于獲取 HTML 里面的圖片來顯示在 TextView 中。

          tagHandler,其作用是把 HTML 帶標(biāo)記的文本內(nèi)容字符串轉(zhuǎn)化成可以顯示效果的的 Spanned 字符串 。由于并非所有的 HTML 標(biāo)簽都可以轉(zhuǎn)化,所以在使用時(shí),用戶需要自己添加一些必要的標(biāo)簽和處理方法時(shí)才會(huì)繼承使用的。

          繼承ImageGetter

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

          繼承TagHandler

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

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

          最后,通過 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 中完成顯示。但是此時(shí)是沒有任何用戶交互的,用戶只能看到 HTML 的內(nèi)容,下面介紹如何添加用戶交互功能。

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

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

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

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

          3.效果

          關(guān)于HTML顯示這部分,沒做具體實(shí)現(xiàn)。具體可以看:靈活高效的在 Android Native App 開發(fā)中顯示 HTML 內(nèi)容(https://www.ibm.com/developerworks/cn/web/1407_zhangqian_androidhtml/index.html),里面有具體源碼可以下載,HTML部分內(nèi)容也是參考該篇文章完成的。

          開源庫:html-textview

          https://github.com/PrivacyApps/html-textview

          6

          總結(jié)

          以上就是關(guān)于圖文混排的一些解決方案,相信通過這些了解,對(duì)于工作中的實(shí)際場(chǎng)景的使用大家會(huì)有適當(dāng)?shù)慕鉀Q方案。由于實(shí)際應(yīng)用較少,所以認(rèn)識(shí)較為淺顯,可能有些地方描述不當(dāng),后期會(huì)考慮封裝個(gè)解決圖文混排的工具類,加深下理解。

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

          2.實(shí)現(xiàn)代碼my_toast_show_view.xml

          <?xml version="1.0" encoding="utf-8"?>
          <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="bottom|center_horizontal"
              android:orientation="vertical">
           
              <LinearLayout
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_marginBottom="150dp"
                  android:background="@drawable/shape_toast_rect_corner"
                  android:gravity="center"
                  android:minWidth="100dp"
                  android:orientation="vertical"
                  android:paddingLeft="5dp"
                  android:paddingTop="5dp"
                  android:paddingRight="5dp"
                  android:paddingBottom="5dp">
           
                  <TextView
                      android:id="@+id/textItem"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:gravity="center"
                      android:lineSpacingMultiplier="1.2"
                      android:maxWidth="450dp"
                      android:paddingLeft="10dp"
                      android:paddingTop="5dp"
                      android:paddingRight="10dp"
                      android:paddingBottom="8dp"
                      android:textColor="#fff"
                      android:textSize="14sp" />
              </LinearLayout>
           
           
          </LinearLayout>

          shape_toast_rect_corner.xml

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

          ToastUtil

          package com.antbyte.listdemo;
           
          import android.content.Context;
          import android.view.Gravity;
          import android.view.LayoutInflater;
          import android.view.View;
          import android.widget.TextView;
          import android.widget.Toast;
           
           
          public class ToastUtil {
           
              //顯示彈出信息
              public static void ToastMessage(String message) {
           
                  Context context = MyApp.mApp;
                  try {
                      View toastRoot = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.my_toast_show_view, null);
                      Toast toast = new Toast(context);
                      toast.setView(toastRoot);
                      TextView tv = (TextView) toastRoot.findViewById(R.id.textItem);
                      tv.setText(message);
                      toast.setGravity(Gravity.BOTTOM, 0, 0);
                      toast.show();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }

          MyApp

          package com.antbyte.listdemo;
           
          import android.app.Application;
           
          public class MyApp extends Application {
           
              public static MyApp mApp;
           
              @Override
              public void onCreate() {
                  super.onCreate();
                  mApp = this;
              }
          }

          3.調(diào)用方法

          ToastUtil.ToastMessage("提示信息");

          主站蜘蛛池模板: 中文国产成人精品久久一区| 一区二区三区高清在线| 国产一区二区三区在线免费观看 | 一区二区三区AV高清免费波多| 成人区精品一区二区不卡| 91亚洲一区二区在线观看不卡| 亚洲一区二区精品视频| 在线观看中文字幕一区| 亚洲一区二区久久| 国产福利精品一区二区| 亚洲国产综合无码一区二区二三区| 亚洲AV无码国产一区二区三区| 久久久av波多野一区二区| 一区二区视频在线观看| 国产一区二区三区不卡AV| 中文字幕一区二区三区免费视频| 一区二区三区中文| 亚洲AV无码一区二三区| 一级毛片完整版免费播放一区| 福利一区二区视频| 一区二区三区免费电影| 一区二区三区在线免费| www一区二区三区| 亚洲午夜精品第一区二区8050| 精品一区二区三区影院在线午夜 | 亚洲一区二区三区国产精品无码 | 精品国产一区二区三区免费看| 成人精品一区二区不卡视频| 精品无码国产AV一区二区三区| 日本无码一区二区三区白峰美 | 爆乳熟妇一区二区三区霸乳| 男人的天堂精品国产一区| 精品一区二区三区在线视频观看| 精品一区二区三区在线视频观看| 日本一区二区高清不卡| 熟女少妇丰满一区二区| 久久久国产精品亚洲一区| 久久精品国内一区二区三区 | 亚洲男女一区二区三区| 五十路熟女人妻一区二区| 欧洲精品一区二区三区|