自定义图文混排视图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));
- private ImageGetter imageGetter = null;
- private Map<String, URLDrawable> imageHashMap = null;
- private ImageGetter GetImageGetter() {
- if(imageHashMap == null) {
- imageHashMap = new HashMap<String, URLDrawable>(2);
- }
- if(imageGetter == null) {
- imageGetter = new ImageGetter() {
- //通过网络获取图片是一个耗时的操作,最好不要放在主线程中,否则容易引起阻塞。
- @Override
- public Drawable getDrawable(String source) {
- String key = MD5.EncoderByMD5(source);
- URLDrawable urlDrawable = imageHashMap.get(key);
- if(urlDrawable == null) {
- urlDrawable = new URLDrawable();
- imageHashMap.put(key, urlDrawable);
- // get the actual source
- ImageGetterAsyncTask.start(mContext, urlDrawable, source, handler);
- }
- return urlDrawable;
- }
- };
- }
- return imageGetter;
- }
- private Handler handler = new Handler() {
- @Override
- public void handleMessage(android.os.Message msg) {
- if(msg.what == ImageGetterAsyncTask.OnDrawablePrepared) {
- refreshNewsImage(msg);
- }
- }
- };
- private void refreshNewsImage(android.os.Message msg) {
- notifyDataSetChanged();
- }
需要设置要显示图片的尺寸:
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
2.
一般在listViewItem中使用都没有问题,但是如果作为scrollView的子视图的话,在有图像时会抛出异常(在公司测试机上如此,其他环境
没有去验证)。建议通过自定义视图的方式来实现,基本思路就是利用SpannableStringBuilder来分割图片及非图片内容,然后逐一创建图
片及非图片视图。对于类似于的新闻呈现且需要高度定制UI的场合非常适用。
2.1 content_textview.xml :用于显示图片之外的内容
- <?xml version="1.0" encoding="utf-8"?>
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/Style_NewsText_Content"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:typeface="normal" >
- </TextView>
2.2 content_imageview.xml:用于显示图片及图片说明,如“[图 1]”
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingTop="5dp">
- <ImageView
- android:id="@+id/content_imageview_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:adjustViewBounds="true"
- android:baselineAlignBottom="true"
- android:contentDescription="@string/xxx"
- android:minHeight="30dp"
- android:minWidth="30dp"
- android:paddingBottom="5dp"
- android:scaleType="centerInside" >
- </ImageView>
- <TextView
- android:id="@+id/content_imageview_title"
- style="@style/Style_NewsText_Content"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingBottom="5dp"
- android:singleLine="false"
- android:textColor="@color/text_b0b0b0"
- android:textSize="@dimen/font_small" >
- </TextView>
- </LinearLayout>
2.3 vertical_linearlayout.xml:根视图,用于插入待显示内容
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- </LinearLayout>
2.4 MyImageTextView.jva:实现图文混排的类
- public class MyImageTextView extends FrameLayout {
- //对应的view
- private LinearLayout mContentView = null;
- //对应的数据
- private CharSequence mData = null;
- private String[] mImageUrl = null;
- private ImageView[] mImage = null;
- private int mImageBaseIndex = 1; //从[图 1]开始
- //是否支持超链接点击
- private Boolean supportMovementMethod = false;
- //是否显示图索引
- private Boolean showImageIndex = false;
- public MyImageTextView(Context context) {
- this(context, null);
- }
- public MyImageTextView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyImageTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
- private void init() {
- setDrawingCacheEnabled(false);
- setClipChildren(false);
- mContentView = (LinearLayout) LayoutInflater.from(getContext()).inflate(
- R.layout.vertical_linearlayout, null);
- addView(mContentView);
- }
- /**
- * 设置待显示内容
- * @param content
- */
- public void setText(CharSequence content) {
- try {
- if(TextUtils.isEmpty(content)) { return; }
- if(content.equals(mData)) { return; }
- mData = content;
- mContentView.removeAllViews(); // 首先清理之前加入的子视图
- int viewIndex = 0;
- int len = content.length();
- SpannableStringBuilder style = new SpannableStringBuilder(content);
- ImageSpan[] imgAry = style.getSpans(0, len, ImageSpan.class);
- if(imgAry == null || imgAry.length <= 0) {
- addTextView(content, viewIndex);
- return;
- }
- int pos = 0;
- int start = 0;
- int end = 0;
- ImageSpan img = null;
- mImageUrl = new String[imgAry.length];
- mImage = new ImageView[imgAry.length];
- for(int i = 0; i < imgAry.length; i++) {
- img = imgAry[i];
- mImageUrl[i] = img.getSource();
- start = style.getSpanStart(img);
- if(pos < start) {
- addTextView(style.subSequence(pos, start), viewIndex++);
- }
- end = style.getSpanEnd(img);
- addImageView(i, viewIndex++);
- pos = end + 1;
- }
- if(pos > 0 && pos < len) {
- addTextView(style.subSequence(pos, len), viewIndex);
- }
- requestLayout();
- invalidate(); //on a UI thread
- } catch(Exception ex) {
- }
- }
- private void addTextView(CharSequence text, int viewIndex) {
- TextView tv = (TextView) LayoutInflater.from(getContext()).inflate(
- R.layout.content_textview, null);
- mContentView.addView(tv, viewIndex);
- tv.setText(text);
- if(supportMovementMethod) {
- changeLink(tv);
- }
- }
- private void addImageView(int index, int viewIndex) {
- View parent = LayoutInflater.from(getContext()).inflate(
- R.layout.content_imageview, null);
- mImage[index] = (ImageView) parent.findViewById(R.id.content_imageview_image);
- TextView tvTitle = (TextView)parent.findViewById(R.id.content_imageview_title);
- if(showImageIndex) {
- //这里的图片标题,也可以通过<img>标签的title/alt等属性分析出来
- tvTitle.setText("[图 " + Integer.toString(mImageBaseIndex + index) + "]");
- tvTitle.setVisibility(View.VISIBLE);
- } else {
- tvTitle.setVisibility(View.GONE);
- }
- mContentView.addView(parent, viewIndex);
- setImage(parent, mImage[index], mImageUrl[index]);
- }
- private void setImage(View parent, ImageView iv, String picUrl){
- if(picUrl != null && picUrl.trim().length() > 0) {
- parent.setVisibility(View.VISIBLE);
- iv.setImageResource(R.drawable.weibo_pic_loading);
- Size size = setPic(iv, picUrl);
- if(size.getHeight() > 0 && size.getWidth() > 0) {
- parent.requestLayout();
- }
- }
- else{
- parent.setVisibility(View.GONE);
- }
- }
- private Size setPic(ImageView logoView, String logoUrl) { //异步加载图片代码略
- return XXXFileManager.getInstance().setImageBitmapWithMemoryCache(
- getContext(), logoView, logoUrl, XXXFileManager.getImagetLrucache(),
- getContext().getClass().getName(), false);
- }
- /**
- * 供图片下载完毕时调用
- * @param fileURL
- */
- public void setPic(String fileURL) {
- if(mImage != null && mImageUrl != null && !TextUtils.isEmpty(fileURL)) {
- String source = null;
- for(int i = 0; i < mImageUrl.length && i < mImage.length; i++) {
- source = mImageUrl[i];
- if(!TextUtils.isEmpty(source)) {
- if(fileURL.equals(source)) {
- setPic(mImage[i], source);
- mImage[i].getParent().requestLayout();
- break;
- }
- }
- }
- }
- }
- /**
- * 设置是否支持超链接点击
- */
- public void setSupportMovementMethod(Boolean supportMovementMethod) {
- this.supportMovementMethod = supportMovementMethod;
- }
- /**
- * 设置是否显示图索引
- * @param showImageIndex
- */
- public void setShowImageIndex(Boolean showImageIndex) {
- this.showImageIndex = showImageIndex;
- }
- /**
- * 设置TextView超链接跳转
- * @param tv
- */
- private void changeLink(TextView tv){
- tv.setMovementMethod(LinkMovementMethod.getInstance());
- CharSequence text = tv.getText();
- if (text instanceof Spannable) {
- int end = text.length();
- Spannable sp = (Spannable) tv.getText();
- URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
- if(urls == null || urls.length <= 0) { return; }
- SpannableStringBuilder style = new SpannableStringBuilder(text);
- URLSpan[] urlsn = style.getSpans(0, end, URLSpan.class);
- if(urlsn == null || urls.length != urlsn.length) { return; }
- //循环把链接发过去
- URLSpan url = null;
- for(int i = 0; i < urls.length && i < urlsn.length; i++) {
- url = urls[i];
- MyURLSpan myURLSpan = new MyURLSpan(getContext(), url.getURL());
- style.removeSpan(urlsn[i]);
- style.setSpan(myURLSpan, sp.getSpanStart(url),
- sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
- }
- tv.setText(style);
- }
- }
- public int getImageCount() {
- int cnt = mImageBaseIndex;
- if(mImage != null && mImageUrl != null) {
- cnt += mImage.length;
- }
- return cnt;
- }
- public void setmImageBaseIndex(int baseIndex) {
- this.mImageBaseIndex = baseIndex;
- }
- public CharSequence getmData() {
- return mData;
- }
- }
2.5 MyURLSpan.java:定义一个可点击的Span,点击超链接时通过浏览器打开改网页/文件。
- public class MyURLSpan extends ClickableSpan {
- private Context context = null;
- private String mUrl = null;;
- public MyURLSpan(Context context,String url) {
- this.context = context;
- this.mUrl = url;
- }
- @Override
- public void onClick(View widget) {
- if (URLUtil.isNetworkUrl(mUrl)) {
- XXXUtils.openMyWebBrowser(this.context,
- this.context.getResources().getString(R.string.newstext_hyperlink),
- this.mUrl);
- }
- }
- }
3 使用简单,可以在xml文件中引用,也可以动态创建视图。
3.1 在xml中引用
- <ScrollView
- android:id="@+id/XXX_ScrollView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
- <LinearLayout
- android:id="@+id/XXX_Parent"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone" >
- ……
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="5dp"
- android:paddingTop="10dp" >
- <XXX.textview.MyImageTextView
- android:id="@+id/XXX_Content"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
- </XXX.textview.MyImageTextView>
- <RelativeLayout
- android:id="@+id/XXX_PayViewParent"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="10dp"
- android:paddingTop="5dp"
- android:visibility="gone" >
- <XXX.textview.MyImageTextView
- android:id="@+id/XXX_PayContent"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:visibility="gone" >
- </XXX.textview.MyImageTextView>
- <RelativeLayout
- android:id="@+id/XXX_PayLock"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/xxx_paylock_bg"
- android:gravity="center_horizontal" >
- <ImageView
- android:id="@+id/xxx_Lock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginRight="5dp"
- android:contentDescription="@string/xxx"
- android:padding="5dp"
- android:src="@drawable/xxx_paylock_icon" >
- </ImageView>
- ……
- </RelativeLayout>
- </RelativeLayout>
- </LinearLayout>
- </LinearLayout>
- </ScrollView>
3.2 java代码,设置显示内容
- itvFreeContent = (MyImageTextView) this.findViewById(R.id.XXX_Content);
- itvFreeContent.setSupportMovementMethod(true);
- //itvFreeContent.setShowImageIndex(true);
- itvFreeContent.setText(Html.fromHtml(formatContent(content)));
当然这里还需要加入图片异步下载完成后的代码,如:
- private void initHandler() {
- this.mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case KLoadImageOver:
- itvFreeContent.setPic(msg.getData().getString("fileURL"));
- break;
- default:
- break;
- }
- }
- };
- }
实际效果图(截取部分):
4 第二种方式需要扩展的是,如果显示的内容有超链接,且超链接时中的显示对象是图片,那么需要给图片增加点击事件,点击的跳转参照MyURLSpan.onClick。
关于图片的下载,这里推荐一个第三方库Android-Universal-Image-Loader。
自定义图文混排视图MyImageTextView的更多相关文章
- android开发 自定义图文混排控件
功能:图文混排,可自动缩放字体,如图: 单点触控使用的代码来自:http://blog.csdn.net/xiaanming/article/details/42833893 谢谢博主! 在该dem ...
- iOS中 图文混排/自定义图文混排 作者:韩俊强
指示根视图:(准备几张图片,把label加载在window上) CustomLable *label = [[CustomLable alloc]initWithFrame:CGRectMake(0, ...
- IOS实现UIButton图文混排、自定义按钮按下和正常状态下不同的背景颜色、根据文字长度自定义UIButton长度
在一些项目中,我们需要自定义自己的UIButton,使Button上面同时具有图片和文字描述,实现自定义UIButton的图文混排. 首先我们需要定义一个继承自UIButton的类,同时实现自己的in ...
- XMPP键盘订制实现图文混排
在现阶段的通信服务中,各种标准都有,因此会出现无法实现相互连通,而XMPP(Extensible Message and presence Protocol)协议的出现,实现了整个及时通信服务协议的互 ...
- iOS 图文混排 链接 可点击
对于这个话题 我想到 1 第一个解决方法就是使用 webView 比较经典 把所有复杂工作都交给控件本身去处理了, 但是好像好多需要自定义的地方 没法从 webView获得响应回调 :(估计也可以实 ...
- [Swift通天遁地]八、媒体与动画-(13)CoreText框架实现图文混排
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- iOS火焰动画效果、图文混排框架、StackView效果、偏好设置、底部手势等源码
iOS精选源码 高性能图文混排框架,构架顺滑的iOS应用. 使用OpenGLE覆盖阿尔法通道视频动画播放器视图. 可选最大日期截至当日日期的日期轮选器ChooseDatePicker 简单轻量的图片浏 ...
- 【iOS】使用CoreText实现图文混排
iOS没有现成的支持图文混排的控件,而要用多个基础控件组合拼成图文混排这样复杂的排版,是件很苦逼的事情.对此的解决方案有使用CoreText进行绘制,或者使用TextKit.本文主要讲解对于CoreT ...
- 高性能图文混排框架,构架顺滑的iOS应用-b
About GallopGallop是一个功能强大.性能优秀的图文混排框架. Features主要用于解决以下需求: 滚动列表的性能优化.Gallop使用异步绘制.视图层级合并.观察mainRunlo ...
随机推荐
- 浅谈JS DDoS攻击原理与防御
分布式拒绝服务攻击(DDoS)攻击是一种针对网站发起的最古老最普遍的攻击.Nick Sullivan是网站加速和安全服务提供商CloudFlare的一名系统工程师.近日,他撰文介绍了攻击者如何利用恶意 ...
- Django Sqlite3 数据库向MySQL迁移
整合了两个URL而来.. 1,http://www.phodal.com/blog/django-mezzanine-sqlite3-migrate-mysql/ 2,http://www.ziqia ...
- Android SwitchCompat 自定义颜色及使用
在Android 5.0 中 Switch 更新了样式 变得 比较好用了 但是在5.0 以下的版本 还是老样子 不实用 因此 就有了 SwitchCompat 来兼容 它是v7 包中的 因此可兼容到 ...
- jinfo命令(Java Configuration Info)
jinfo可以输出并修改运行时的java 进程的opts.用处比较简单,用于输出JAVA系统参数及命令行参数.用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jin ...
- Android清除本地数据缓存代码
/* * 文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除sharedPreference,清除files和清除自定义目 ...
- 清除nginx静态资源缓存
之前写过一篇如何配置nginx缓存及手动清除缓存的文章: http://www.cnblogs.com/Eivll0m/p/4921829.html 但如果有大量缓存需要清理,手动一条条清理就比较慢了 ...
- mkimage使用详解
uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件. mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字 ...
- 数据结构(启发式合并):HNOI 2009 梦幻布丁
Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input 第 ...
- Android项目开发全程(二)--Afinal用法简单介绍
本篇博文接上篇的<Android项目开发全程(一)--创建工程>,主要介绍一下在本项目中用到的一个很重要的框架-Afinal,由于本系列博文重点是项目开发全程,所以在这里就先介绍一下本项目 ...
- 使用Codis搭建redis集群服务
转(http://www.jianshu.com/p/f8e968e57863) 一. 应用场景 redis 作为数据结构存储引擎,有着很多优点 高性能单机引擎可以达到5-10W qps 数据结构全面 ...