zoukankan      html  css  js  c++  java
  • 自定义图文混排视图MyImageTextView

    http://blog.csdn.net/xujunfeng000/article/details/36399339?utm_source=tuicool&utm_medium=referral

    TextView本身是支持图文混排的,在手机上,通过TextView进行图文混排时,排版可能难以达到PC上浏览器的效果,特别是对于一些支持多种标签的发布系统。


    1. 网上很容易找到的使用TextView实现图文混排的例子,大多是类似于下面的形式:

    TextView tv_Content;

    tv_Content.setText(Html.fromHtml(item.getContent(), GetImageGetter(), null));


    1. private ImageGetter imageGetter = null;  
    2. private Map<String, URLDrawable> imageHashMap = null;   
    3. private ImageGetter GetImageGetter() {  
    4.     if(imageHashMap == null) {  
    5.         imageHashMap = new HashMap<String, URLDrawable>(2);             
    6.     }  
    7.     if(imageGetter == null) {  
    8.         imageGetter = new ImageGetter() {     
    9.             //通过网络获取图片是一个耗时的操作,最好不要放在主线程中,否则容易引起阻塞。  
    10.             @Override  
    11.             public Drawable getDrawable(String source) {  
    12.                 String key = MD5.EncoderByMD5(source);  
    13.                 URLDrawable urlDrawable = imageHashMap.get(key);  
    14.                 if(urlDrawable == null) {  
    15.                     urlDrawable = new URLDrawable();  
    16.                     imageHashMap.put(key, urlDrawable);  
    17.                     // get the actual source  
    18.                     ImageGetterAsyncTask.start(mContext, urlDrawable, source, handler);                       
    19.                 }  
    20.                 return urlDrawable;  
    21.             }  
    22.         };  
    23.     }  
    24.     return imageGetter;  
    25. }  
    26.   
    27. private Handler handler = new Handler() {  
    28.     @Override  
    29.     public void handleMessage(android.os.Message msg) {  
    30.         if(msg.what == ImageGetterAsyncTask.OnDrawablePrepared) {  
    31.             refreshNewsImage(msg);  
    32.         }  
    33.     }  
    34. };  
    35.   
    36. private void refreshNewsImage(android.os.Message msg) {  
    37.     notifyDataSetChanged();  
    38. }  


    需要设置要显示图片的尺寸:

    drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());


    2. 一般在listViewItem中使用都没有问题,但是如果作为scrollView的子视图的话,在有图像时会抛出异常(在公司测试机上如此,其他环境 没有去验证)。建议通过自定义视图的方式来实现,基本思路就是利用SpannableStringBuilder来分割图片及非图片内容,然后逐一创建图 片及非图片视图。对于类似于的新闻呈现且需要高度定制UI的场合非常适用。


    2.1 content_textview.xml :用于显示图片之外的内容

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <TextView xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     style="@style/Style_NewsText_Content"  
    4.     android:layout_width="fill_parent"  
    5.     android:layout_height="wrap_content"  
    6.     android:paddingLeft="10dp"  
    7.     android:paddingRight="10dp"  
    8.     android:typeface="normal" >  
    9.   
    10. </TextView>  


    2.2 content_imageview.xml:用于显示图片及图片说明,如“[图 1]”

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="fill_parent"  
    4.     android:layout_height="wrap_content"  
    5.     android:layout_gravity="center_horizontal"  
    6.     android:orientation="vertical"   
    7.     android:paddingTop="5dp">  
    8.   
    9.     <ImageView  
    10.         android:id="@+id/content_imageview_image"  
    11.         android:layout_width="wrap_content"  
    12.         android:layout_height="wrap_content"  
    13.         android:layout_gravity="center_horizontal"  
    14.         android:adjustViewBounds="true"  
    15.         android:baselineAlignBottom="true"  
    16.         android:contentDescription="@string/xxx"  
    17.         android:minHeight="30dp"  
    18.         android:minWidth="30dp"  
    19.         android:paddingBottom="5dp"  
    20.         android:scaleType="centerInside" >  
    21.   
    22.     </ImageView>  
    23.   
    24.     <TextView  
    25.         android:id="@+id/content_imageview_title"  
    26.         style="@style/Style_NewsText_Content"  
    27.         android:layout_width="fill_parent"  
    28.         android:layout_height="wrap_content"  
    29.         android:gravity="center"  
    30.         android:paddingBottom="5dp"  
    31.         android:singleLine="false"  
    32.         android:textColor="@color/text_b0b0b0"  
    33.         android:textSize="@dimen/font_small" >  
    34.     </TextView>  
    35.   
    36. </LinearLayout>  


    2.3 vertical_linearlayout.xml:根视图,用于插入待显示内容

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="fill_parent"  
    4.     android:layout_height="wrap_content"  
    5.     android:orientation="vertical" >  
    6.       
    7.   
    8. </LinearLayout>  



    2.4 MyImageTextView.jva:实现图文混排的类

    1. public class MyImageTextView extends FrameLayout {  
    2.     //对应的view  
    3.     private LinearLayout mContentView = null;  
    4.       
    5.     //对应的数据  
    6.     private CharSequence mData = null;  
    7.     private String[] mImageUrl = null;  
    8.     private ImageView[] mImage = null;  
    9.     private int mImageBaseIndex = 1; //从[图 1]开始  
    10.       
    11.     //是否支持超链接点击  
    12.     private Boolean supportMovementMethod = false;  
    13.     //是否显示图索引  
    14.     private Boolean showImageIndex = false;  
    15.       
    16.     public MyImageTextView(Context context) {  
    17.         this(context, null);  
    18.     }  
    19.   
    20.     public MyImageTextView(Context context, AttributeSet attrs) {  
    21.         this(context, attrs, 0);  
    22.     }  
    23.   
    24.     public MyImageTextView(Context context, AttributeSet attrs, int defStyle) {  
    25.         super(context, attrs, defStyle);  
    26.           
    27.         init();  
    28.     }  
    29.       
    30.     private void init() {  
    31.         setDrawingCacheEnabled(false);  
    32.         setClipChildren(false);  
    33.           
    34.         mContentView = (LinearLayout) LayoutInflater.from(getContext()).inflate(  
    35.                 R.layout.vertical_linearlayout, null);  
    36.         addView(mContentView);  
    37.     }  
    38.       
    39.     /** 
    40.      * 设置待显示内容 
    41.      * @param content 
    42.      */  
    43.     public void setText(CharSequence content) {  
    44.         try {                     
    45.             if(TextUtils.isEmpty(content)) { return; }  
    46.             if(content.equals(mData)) { return; }  
    47.             mData = content;  
    48.             mContentView.removeAllViews(); // 首先清理之前加入的子视图  
    49.               
    50.             int viewIndex = 0;  
    51.             int len = content.length();  
    52.             SpannableStringBuilder style = new SpannableStringBuilder(content);       
    53.             ImageSpan[] imgAry = style.getSpans(0, len, ImageSpan.class);  
    54.             if(imgAry == null || imgAry.length <= 0) {  
    55.                 addTextView(content, viewIndex);  
    56.                 return;   
    57.             }  
    58.               
    59.             int pos = 0;  
    60.             int start = 0;   
    61.             int end = 0;  
    62.             ImageSpan img = null;  
    63.             mImageUrl = new String[imgAry.length];  
    64.             mImage = new ImageView[imgAry.length];  
    65.             for(int i = 0; i < imgAry.length; i++) {  
    66.                 img = imgAry[i];  
    67.                 mImageUrl[i] = img.getSource();  
    68.                 start = style.getSpanStart(img);  
    69.                 if(pos < start) {  
    70.                     addTextView(style.subSequence(pos, start), viewIndex++);  
    71.                 }  
    72.                 end = style.getSpanEnd(img);  
    73.                 addImageView(i, viewIndex++);  
    74.                   
    75.                 pos = end + 1;  
    76.             }  
    77.               
    78.             if(pos > 0 && pos < len) {  
    79.                 addTextView(style.subSequence(pos, len), viewIndex);  
    80.             }  
    81.               
    82.             requestLayout();  
    83.             invalidate(); //on a UI thread  
    84.         } catch(Exception ex) {  
    85.               
    86.         }  
    87.     }  
    88.   
    89.     private void addTextView(CharSequence text, int viewIndex) {  
    90.         TextView tv = (TextView) LayoutInflater.from(getContext()).inflate(  
    91.                 R.layout.content_textview, null);         
    92.         mContentView.addView(tv, viewIndex);  
    93.         tv.setText(text);  
    94.           
    95.         if(supportMovementMethod) {  
    96.             changeLink(tv);  
    97.         }  
    98.     }  
    99.   
    100.     private void addImageView(int index, int viewIndex) {  
    101.         View parent = LayoutInflater.from(getContext()).inflate(  
    102.                 R.layout.content_imageview, null);  
    103.         mImage[index] = (ImageView) parent.findViewById(R.id.content_imageview_image);  
    104.         TextView tvTitle = (TextView)parent.findViewById(R.id.content_imageview_title);  
    105.         if(showImageIndex) {  
    106.             //这里的图片标题,也可以通过<img>标签的title/alt等属性分析出来  
    107.             tvTitle.setText("[图 " + Integer.toString(mImageBaseIndex + index) + "]");  
    108.             tvTitle.setVisibility(View.VISIBLE);  
    109.         } else {  
    110.             tvTitle.setVisibility(View.GONE);  
    111.         }  
    112.         mContentView.addView(parent, viewIndex);  
    113.           
    114.         setImage(parent, mImage[index], mImageUrl[index]);  
    115.     }  
    116.       
    117.     private void setImage(View parent, ImageView iv, String picUrl){  
    118.         if(picUrl != null && picUrl.trim().length() > 0) {  
    119.             parent.setVisibility(View.VISIBLE);  
    120.           
    121.             iv.setImageResource(R.drawable.weibo_pic_loading);  
    122.             Size size = setPic(iv, picUrl);  
    123.             if(size.getHeight() > 0 && size.getWidth() > 0) {  
    124.                 parent.requestLayout();  
    125.             }  
    126.         }  
    127.         else{  
    128.             parent.setVisibility(View.GONE);  
    129.         }  
    130.     }  
    131.       
    132.     private Size setPic(ImageView logoView, String logoUrl) { //异步加载图片代码略         
    133.         return XXXFileManager.getInstance().setImageBitmapWithMemoryCache(  
    134.                 getContext(), logoView, logoUrl, XXXFileManager.getImagetLrucache(),  
    135.                 getContext().getClass().getName(), false);  
    136.     }  
    137.       
    138.     /** 
    139.      * 供图片下载完毕时调用 
    140.      * @param fileURL 
    141.      */  
    142.     public void setPic(String fileURL) {  
    143.         if(mImage != null && mImageUrl != null && !TextUtils.isEmpty(fileURL)) {  
    144.             String source = null;  
    145.             for(int i = 0; i < mImageUrl.length && i < mImage.length; i++) {  
    146.                 source = mImageUrl[i];  
    147.                 if(!TextUtils.isEmpty(source)) {  
    148.                     if(fileURL.equals(source)) {  
    149.                         setPic(mImage[i], source);  
    150.                         mImage[i].getParent().requestLayout();  
    151.                         break;  
    152.                     }  
    153.                 }  
    154.             }  
    155.         }  
    156.     }  
    157.   
    158.     /** 
    159.      * 设置是否支持超链接点击 
    160.      */  
    161.     public void setSupportMovementMethod(Boolean supportMovementMethod) {  
    162.         this.supportMovementMethod = supportMovementMethod;  
    163.     }  
    164.   
    165.     /** 
    166.      * 设置是否显示图索引 
    167.      * @param showImageIndex 
    168.      */  
    169.     public void setShowImageIndex(Boolean showImageIndex) {  
    170.         this.showImageIndex = showImageIndex;  
    171.     }  
    172.   
    173.     /** 
    174.      * 设置TextView超链接跳转 
    175.      * @param tv 
    176.      */  
    177.     private void changeLink(TextView tv){  
    178.         tv.setMovementMethod(LinkMovementMethod.getInstance());  
    179.         CharSequence text = tv.getText();     
    180.         if (text instanceof Spannable) {     
    181.             int end = text.length();     
    182.             Spannable sp = (Spannable) tv.getText();     
    183.             URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);  
    184.             if(urls == null || urls.length <= 0) { return; }  
    185.             SpannableStringBuilder style = new SpannableStringBuilder(text);  
    186.             URLSpan[] urlsn = style.getSpans(0, end, URLSpan.class);  
    187.             if(urlsn == null || urls.length != urlsn.length) { return; }  
    188.               
    189.             //循环把链接发过去  
    190.             URLSpan url = null;  
    191.             for(int i = 0; i < urls.length && i < urlsn.length; i++) {  
    192.                 url = urls[i];   
    193.                 MyURLSpan myURLSpan = new MyURLSpan(getContext(), url.getURL());  
    194.                 style.removeSpan(urlsn[i]);  
    195.                 style.setSpan(myURLSpan, sp.getSpanStart(url),     
    196.                         sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);     
    197.             }  
    198.             tv.setText(style);  
    199.         }  
    200.     }  
    201.   
    202.     public int getImageCount() {  
    203.         int cnt = mImageBaseIndex;  
    204.         if(mImage != null && mImageUrl != null) {  
    205.             cnt += mImage.length;  
    206.         }  
    207.         return cnt;  
    208.     }  
    209.   
    210.     public void setmImageBaseIndex(int baseIndex) {  
    211.         this.mImageBaseIndex = baseIndex;  
    212.     }  
    213.   
    214.     public CharSequence getmData() {  
    215.         return mData;  
    216.     }  
    217.       
    218. }  


    2.5 MyURLSpan.java:定义一个可点击的Span,点击超链接时通过浏览器打开改网页/文件。

    1. public class MyURLSpan extends ClickableSpan {  
    2.     private Context context = null;  
    3.     private String mUrl     = null;;  
    4.   
    5.     public MyURLSpan(Context context,String url) {  
    6.         this.context = context;  
    7.         this.mUrl = url;  
    8.     }  
    9.   
    10.     @Override  
    11.     public void onClick(View widget) {  
    12.         if (URLUtil.isNetworkUrl(mUrl)) {  
    13.             XXXUtils.openMyWebBrowser(this.context,  
    14.                     this.context.getResources().getString(R.string.newstext_hyperlink),  
    15.                     this.mUrl);  
    16.         }  
    17.     }  
    18. }  


    3 使用简单,可以在xml文件中引用,也可以动态创建视图。

    3.1 在xml中引用

    1. <ScrollView  
    2.     android:id="@+id/XXX_ScrollView"  
    3.     android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent" >  
    5.   
    6.     <LinearLayout  
    7.         android:id="@+id/XXX_Parent"  
    8.         android:layout_width="fill_parent"  
    9.         android:layout_height="wrap_content"  
    10.         android:orientation="vertical"  
    11.         android:visibility="gone" >  
    12.   
    13.         ……  
    14.   
    15.         <LinearLayout  
    16.             android:layout_width="fill_parent"  
    17.             android:layout_height="wrap_content"  
    18.             android:orientation="vertical"  
    19.             android:paddingBottom="5dp"  
    20.             android:paddingTop="10dp" >  
    21.   
    22.             <XXX.textview.MyImageTextView  
    23.                 android:id="@+id/XXX_Content"  
    24.                 android:layout_width="fill_parent"  
    25.                 android:layout_height="wrap_content"  
    26.                 android:paddingLeft="10dp"  
    27.                 android:paddingRight="10dp" >  
    28.             </XXX.textview.MyImageTextView>  
    29.   
    30.             <RelativeLayout  
    31.                 android:id="@+id/XXX_PayViewParent"  
    32.                 android:layout_width="fill_parent"  
    33.                 android:layout_height="wrap_content"  
    34.                 android:paddingBottom="10dp"  
    35.                 android:paddingTop="5dp"  
    36.                 android:visibility="gone" >  
    37.   
    38.                 <XXX.textview.MyImageTextView  
    39.                     android:id="@+id/XXX_PayContent"  
    40.                     android:layout_width="fill_parent"  
    41.                     android:layout_height="wrap_content"  
    42.                     android:paddingLeft="10dp"  
    43.                     android:paddingRight="10dp"  
    44.                     android:visibility="gone" >  
    45.                 </XXX.textview.MyImageTextView>  
    46.   
    47.                 <RelativeLayout  
    48.                     android:id="@+id/XXX_PayLock"  
    49.                     android:layout_width="fill_parent"  
    50.                     android:layout_height="wrap_content"  
    51.                     android:background="@drawable/xxx_paylock_bg"  
    52.                     android:gravity="center_horizontal" >  
    53.   
    54.                     <ImageView  
    55.                         android:id="@+id/xxx_Lock"  
    56.                         android:layout_width="wrap_content"  
    57.                         android:layout_height="wrap_content"  
    58.                         android:layout_centerVertical="true"  
    59.                         android:layout_marginRight="5dp"  
    60.                         android:contentDescription="@string/xxx"  
    61.                         android:padding="5dp"  
    62.                         android:src="@drawable/xxx_paylock_icon" >  
    63.                     </ImageView>  
    64.   
    65.                     ……  
    66.                 </RelativeLayout>  
    67.             </RelativeLayout>  
    68.         </LinearLayout>  
    69.     </LinearLayout>  
    70. </ScrollView>  


    3.2 java代码,设置显示内容

    1. itvFreeContent = (MyImageTextView) this.findViewById(R.id.XXX_Content);  
    2. itvFreeContent.setSupportMovementMethod(true);  
    3. //itvFreeContent.setShowImageIndex(true);  
    4. itvFreeContent.setText(Html.fromHtml(formatContent(content)));  

    当然这里还需要加入图片异步下载完成后的代码,如:

    1. private void initHandler() {  
    2.     this.mHandler = new Handler() {  
    3.         @Override  
    4.         public void handleMessage(Message msg) {  
    5.             switch (msg.what) {  
    6.             case KLoadImageOver:  
    7.                 itvFreeContent.setPic(msg.getData().getString("fileURL"));  
    8.                 break;  
    9.             default:  
    10.                 break;  
    11.             }  
    12.         }  
    13.     };  
    14. }  

    实际效果图(截取部分):


    4 第二种方式需要扩展的是,如果显示的内容有超链接,且超链接时中的显示对象是图片,那么需要给图片增加点击事件,点击的跳转参照MyURLSpan.onClick。

    关于图片的下载,这里推荐一个第三方库Android-Universal-Image-Loader

  • 相关阅读:
    java面向对象day01
    找工作——JVM内存管理
    找工作——多线程
    找工作-——网络IO
    找工作--volatile
    找工作——异常处理
    找工作--设计模式
    Sqoop安装
    NIO
    Hadoop源码编译
  • 原文地址:https://www.cnblogs.com/misybing/p/4975639.html
Copyright © 2011-2022 走看看