Android TextView加载html图片详解

转至:http://blog.csdn.net/johnsonblog/article/details/7741972

       学Android的时候突然想到一个问题:怎么用TextView控件显示带有格式的文字,可否使用Html布局?查了下Android 帮助文档,其提供了android.text.Html类和Html.ImageGetter、Html.TagHandler接口

        其实本不打算写这篇博文的,但看到网络上关于此的文章,基本是:你抄我,我抄你,大家抄来抄去,有用的也就那么一两篇文章,而且说得不明不白,网络就是如此,盗版也成为了一种文化,这就是所谓的拿来主义吧。当然不否认大牛的辛勤劳作,写出的高质量文章;其次是学以致用,个人习惯--总结一下。

先看截图:

               

        我们平常使用TextView的setText()方法传递String参数的时候其实是调用的public final void setText (CharSequence text)方法:

[java]   view plain  copy
  1. /** 
  2.     * Sets the string value of the TextView. TextView does not accept 
  3.     * HTML-like formatting, which you can do with text strings in XML resource files. 
  4.     * To style your strings, attach android.text.style.* objects to a 
  5.     * {@link android.text.SpannableString SpannableString}, or see the 
  6.     *  
  7.     * Available Resource Types documentation for an example of setting  
  8.     * formatted text in the XML resource file. 
  9.     * 
  10.     * @attr ref android.R.styleable#TextView_text 
  11.     */  
  12.    @android.view.RemotableViewMethod  
  13.    public final void setText(CharSequence text) {  
  14.        setText(text, mBufferType);  
  15.    }  
        而String类是CharSequence的子类,在CharSequence子类中有一个接口Spanned,即类似html的带标记的文本,我们可以用它来在TextView中显示html。在上面Android源码注释中有提及TextView does not accept HTML-like formatting。

       android.text.Html类共提供了三个方法,可以到Android帮助文档查看。

[java]   view plain  copy
  1. public static Spanned fromHtml (String source)  
  2.   
  3. public static Spanned fromHtml (String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler)  
  4.   
  5. public static String toHtml (Spanned text)  


       通过使用第一个方法,可以将Html显示在TextView中:

[java]   view plain  copy
  1. public void onCreate(Bundle savedInstanceState) {  
  2.         super.onCreate(savedInstanceState);  
  3.         setContentView(R.layout.main);  
  4.   
  5.         TextView tv=(TextView)findViewById(R.id.textView1);  
  6.         String html="TextView使用HTML

    强调

    斜体

    "
      
  7.                 +"

    超链接HTML入门学习HTML!

    颜色1"  

  8.                 +"

    颜色2

    标题1

    标题2

    标题3

    大于>小于<

    " +  

  9.                 "下面是网络图片

    "
    ;  
  10.           
  11.         tv.setMovementMethod(ScrollingMovementMethod.getInstance());//滚动  
  12.         tv.setText(Html.fromHtml(html));      
  13.     }  
效果:

              
        可以看出,字体效果是显示出来了,但是图片却没有显示。要实现图片的显示需要使用Html.fromHtml的另外一个重构方法:public static Spanned fromHtml (String source, Html.ImageGetterimageGetter, Html.TagHandler tagHandler)其中Html.ImageGetter是一个接口,我们要实现此接口,在它的getDrawable(String source)方法中返回图片的Drawable对象才可以。
修改后的代码:

[java]   view plain  copy
  1. ImageGetter imgGetter = new Html.ImageGetter() {  
  2.         public Drawable getDrawable(String source) {  
  3.               Drawable drawable = null;  
  4.               URL url;    
  5.               try {     
  6.                   url = new URL(source);    
  7.                   drawable = Drawable.createFromStream(url.openStream(), "");  //获取网路图片  
  8.               } catch (Exception e) {    
  9.                   return null;    
  10.               }    
  11.               drawable.setBounds(00, drawable.getIntrinsicWidth(), drawable  
  12.                             .getIntrinsicHeight());  
  13.               return drawable;   
  14.         }  
  15. };  

这里主要是实现了Html.ImageGetter接口,通过图片的URL地址获取相应的Drawable实例。
不要忘了在Mainifest文件中加入网络访问的权限:

[java]   view plain  copy
  1. "android.permission.INTERNET" />  

 友情提示:通过网络获取图片是一个耗时的操作,最好不要放在主线程中,否则容易引起阻塞。
上面介绍的是显示网络上的图片,但如何显示本地的图片呢:


[java]   view plain  copy
  1.    ImageGetter imgGetter = new Html.ImageGetter() {  
  2.         public Drawable getDrawable(String source) {  
  3.               Drawable drawable = null;  
  4.                  
  5.               drawable = Drawable.createFromPath(source); //显示本地图片  
  6.               drawable.setBounds(00, drawable.getIntrinsicWidth(), drawable  
  7.                             .getIntrinsicHeight());  
  8.               return drawable;   
  9.         }  
  10. };  
只需将source改为本地图片的路径便可,在这里我使用的是:
[java]   view plain  copy
  1. String source;  
  2. source=getFilesDir()+"/ic_launcher.png";  


我的小站:Android TextView使用HTML处理字体样式、显示图片


THE END



转至:http://52xianmengyu.iteye.com/blog/1747646


一、[Android实例]实现TextView里的文字有不同颜色

转eoe:http://www.eoeandroid.com/thread-4496-1-1.html

import android.text.Html;

TextView t3 = (TextView) findViewById(R.id.text3);
        t3.setText(
            Html.fromHtml(
                "text3:  Text with a " +
                "link " +
                "created in the Java source code using HTML."));

二、TextView显示html文件中的图片

转javaeye:http://da-en.javaeye.com/blog/712415

我们知道要让TextView解析和显示Html代码。可以使用
Spanned text = Html.fromHtml(source);
tv.setText(text);
来实现,这个用起来简单方便。
但是,怎样让TextView也显示Html中节点的图像呢?

我们可以看到fromHtml还有另一个重构:
fromHtml(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler)

实现一下ImageGetter就可以让图片显示了:
ImageGetter imgGetter = new Html.ImageGetter() {
             @Override
             public Drawable getDrawable(String source) {
                   Drawable drawable = null;
                   drawable = Drawable.createFromPath(source);  // Or fetch it from the URL
                   // Important
                   drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable
                                 .getIntrinsicHeight());
                   return drawable;
             }
};

至于TagHandler,我们这里不需要使用,可以直接传null。
参考文档:
http://tech-droid.blogspot.com/2010/06/textview-with-html-content.html英语好的朋友就直接看英文文档吧。

三、Android---文字中插入表情

    转载自:http://blog.163.com/spf9190@126/blog/static/50207531201091545954587/

       这段时间在做一个短信项目,需要实现短信中插入表情的功能,本一位非常困难,经过一段时间的研究,发现还是比较簡単的,现在总结如下。

       以短信输入框为例,短信的输入框是一个EditText,它的append方法不仅可以加入字符串,还可以添加HTML标记。以下就是使用HTML标记添加表情的具体操作。

   首先需要构建一个ImageGetter,作用是通过HTML标记获得对应在res目录下的图片:

       ImageGetter imageGetter = new ImageGetter() {  
        @Override
       public Drawable getDrawable(String source) {
       int id = Integer.parseInt(source);

      //根据id从资源文件中获取图片对象
       Drawable d = getResources().getDrawable(id);
       d.setBounds(0, 0, d.getIntrinsicWidth(),d.getIntrinsicHeight());
        return d;
       }
       };          

然后就可以直接往EditText视图中添加

       inputLable.append(Html.fromHtml("", imageGetter, null));                  

  其中 Html.fromHtml(""就是HTML的图片标记,在Android中支持了部分HTML标记的使用(这方面我还在继续研究),HTML标记必须被Html.fromHtml修饰。imageGetter即为之前创建的ImageGetter类型的对象。

很简单的几句代码就解决了问题,不仅在EditText中,在TextView中同样可以这样插入图片。

效果图:

四、android 短信字符转表情显示过程
android 的短信实现方式普通用户适应的话需要长时间的使用才能习惯,将andorid的短信模式设置成我们常用的(一般人用户)的习惯。在查看字符转图片的过程中可以猜测出腾讯的QQ表情的原理应该是一样的只是在传送非常用的表情时是将byte数据转换为image.

以下代码摘录至android源码里面的MMS项目,其中的

package com.android.mms.ui 里的 MessageListItem.java

package com.android.mms.util 里的 SmileyParser.java

/***
     * 
         * 
此方法描述的是:   注意此方法在做表情转换的准备了

         * @author:[email protected],[email protected]
         * @version: 2010-5-13 
下午03:31:13
     */
    private void bindCommonMessage(final MessageItem msgItem) {
        if (mDownloadButton != null) {
            mDownloadButton.setVisibility(View.GONE);
            mDownloadingLabel.setVisibility(View.GONE);
        }
        // Since the message text should be concatenated with the sender's
        // address(or name), I have to display it here instead of
        // displaying it by the Presenter.
        mBodyTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());

        // Get and/or lazily set the formatted message from/on the
        // MessageItem. Because the MessageItem instances come from a
        // cache (currently of size ~50), the hit rate on avoiding the
        // expensive formatMessage() call is very high.
        CharSequence formattedMessage = msgItem.getCachedFormattedMessage();
        if (formattedMessage == null) { //
肯定为null应为msgItem.formattedMessage从诞生来就没被注意过一次

            formattedMessage = formatMessage(msgItem.mContact, msgItem.mBody,   //
重点到了
                                             msgItem.mSubject, msgItem.mTimestamp,
                                             msgItem.mHighlight);
            msgItem.setCachedFormattedMessage(formattedMessage);
        }
        mBodyTextView.setText(formattedMessage);

        if (msgItem.isSms()) {
            hideMmsViewIfNeeded();
        } else {
            Presenter presenter = PresenterFactory.getPresenter(
                    "MmsThumbnailPresenter", mContext,
                    this, msgItem.mSlideshow);
            presenter.present();

            if (msgItem.mAttachmentType != WorkingMessage.TEXT) {
                inflateMmsView();
                mMmsView.setVisibility(View.VISIBLE);
                setOnClickListener(msgItem);
                drawPlaybackButton(msgItem);
            } else {
                hideMmsViewIfNeeded();
            }
        }

        drawLeftStatusIndicator(msgItem.mBoxId);
        drawRightStatusIndicator(msgItem);
    }
//------------------------------------------------------------------------------

/***
     * 
         * 
此方法描述的是:   开始转换了哦

         * @author:[email protected],[email protected]
         * @version: 2010-5-13 
下午03:32:52
     */
    private CharSequence formatMessage(String contact, String body, String subject,
                                       String timestamp, String highlight) {
        CharSequence template = mContext.getResources().getText(R.string.name_colon); //
遇到鬼了     <主题:
%s>"
        SpannableStringBuilder buf =                   //
把他当作StringBuffer只是它可以放的不是 String 而已他能放跟多类型的东西

            new SpannableStringBuilder(TextUtils.replace(template,
                new String[] { "%s" },
                new CharSequence[] { contact })); //
替换成联系人

        boolean hasSubject = !TextUtils.isEmpty(subject); //主题
        if (hasSubject) {
            buf.append(mContext.getResources().getString(R.string.inline_subject, subject)); //buff
先在是 联系人 主题 XXXX      eg wuyi <主题:dsadasdsa> 我爱我家
        }

        if (!TextUtils.isEmpty(body)) {
            if (hasSubject) {
                buf.append(" - "); //
如果内容有主题有就+ " - "    eg wuyi <主题
:sdsadsadsa> - 
            }
            SmileyParser parser = SmileyParser.getInstance(); //
获得表情类了哦

            buf.append(parser.addSmileySpans(body)); //
追查 急切关注中
        }
        if (!TextUtils.isEmpty(timestamp)) {
            buf.append("\n");
            int startOffset = buf.length();

            // put a one pixel high spacer line between the message and the time stamp as requested
            // by the spec.
            //
把之间的信息和时间戳的要求间隔一个像素的高线

            //
由规范
            buf.append("\n");
            buf.setSpan(new AbsoluteSizeSpan(3), startOffset, buf.length(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

            startOffset = buf.length();
            buf.append(timestamp);
            buf.setSpan(new AbsoluteSizeSpan(12), startOffset, buf.length(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            // Make the timestamp text not as dark 
改变某区域颜色   时间的地方为特殊颜色

            int color = mContext.getResources().getColor(R.color.timestamp_color);
            buf.setSpan(new ForegroundColorSpan(color), startOffset, buf.length(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (highlight != null) {
            int highlightLen = highlight.length();

            String s = buf.toString().toLowerCase();
            int prev = 0;
            while (true) {
                int index = s.indexOf(highlight, prev);
                if (index == -1) {
                    break;
                }
                buf.setSpan(new StyleSpan(Typeface.BOLD), index, index + highlightLen, 0);
                prev = index + highlightLen;
            }
        }
        return buf;
    }

//------------------------------------------------------------

/**
     * Adds ImageSpans to a CharSequence that replace textual emoticons such
     * as :-) with a graphical version.
     * 
     * @param text A CharSequence possibly containing emoticons
     * @return A CharSequence annotated with ImageSpans covering any
     *         recognized emoticons.
     * 
添加ImageSpans一个CharSequence的表情符号代替文字等     *如用图形版本:-)

     * 
核心是把表情字符替换成ImageSpans的对象
     */
    public CharSequence addSmileySpans(CharSequence text) {
        SpannableStringBuilder builder = new SpannableStringBuilder(text);

        Matcher matcher = mPattern.matcher(text);
        while (matcher.find()) {
            int resId = mSmileyToRes.get(matcher.group());
            //
注意下面的一块有点不好理解哦但是是核心

            builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        return builder;
    }

总结:

     android 在将字符转化为表情图像其核心代码为

builder.setSpan(new ImageSpan(mContext, resId), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
原理过程是先匹配到表情字符然后通过new ImageSpan(上下文,表情地址)绘制出一个ImageView然后替换掉表情字符。


五、  

Android TextView 支持的HTML标签

转自:http://www.cnblogs.com/playing/archive/2011/03/17/1987033.html


你可能感兴趣的:(Android>>进阶)