Android开发Android开发经验谈程序员

详解Android“图文混排”实现方式

2019-05-07  本文已影响12人  Android架构

在使用TextView的时候,我们经常需要在TextView中进行图文混排,比如在QQ中聊天的消息中的表情,底部tab图标等。

一、场景

二、实现方式

Android官方对TextView的图文混排提供了支持,我们可以从以下三种方式实现TextView的图文混排:

1.在TextView中使用Compound Drawable属性;
2.在TextView中使用Spannable多样式显示;
3.在TextView中显示HTML文本。

三、drawable属性

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

一共有两种方式可以实现:XML布局设置和Java代码设置。

1. xml布局

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

android:drawableLeft 在文字左边设置图片
android:drawableTop 在文字上边设置图片
android:drawableRight 在文字右边设置图片
android:drawableBottom 在文字下边设置图片
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 设置上下左右位置的图片
setCompoundDrawablesRelative 设置四周的图片,其中两边对应xml中的start,end
setCompoundDrawablesWithIntrinsicBounds 设置上下左右位置的图片,图片有默认的边界
setCompoundDrawablesRelativeWithIntrinsicBounds 设置四周的图片,图片有默认的边界
setCompoundDrawablePadding 设置图片与文字之间的间距

3.缺陷

当TextView设置成固定大小时,由于文字距离边界的距离过大,会导致文字与图片之间设置的间距无效,如下图。

解决方案:

①设置TextView的内填充

通过设置paddingLeft、paddingRight、paddingTop、paddingBottom来缩写这个间距

②自定义TextView重新布局

a.先自定义属性iconPadding来设置间距,并提供方法给外部调用。

b.重写setCompoundDrawablesWithIntrinsicBounds()方法来获取我们设置的drawable宽高。

c.最后重写onLayout方法。

可以先参考:Android技巧 - drawablePadding的问题,该篇文章只解决了左右失效的问题。后期会整理个解决图文混排的工具库,里面会有具体方案。

四、Spannable使用

1.简介

setText(CharSequence text)中接收的是CharSequence。而SpannableString和SpannableStringBuilder是其实现类,是可以直接赋值的。并且两者的setSpan()方法可以设置一些格式对象(例如字体大小、下划线、替换为图片等),这就可以实现富文本了。

Spannable实现子类:SpannableString,SpannableStringBuilder(可变,类似于StringBuilder)。

Spannable中定义了抽象方法:setSpan(Object what, int start, int end, int flags)和removeSpan(Object what)。这两个方法实现了对字符串的灵活编辑。

其中setSpan()方法包含如下参数:

参数 参数说明
what span样式
start 样式开始的索引
end 样式结束的索引
flags 样式作用的范围

flags常用的有四种

SPAN_INCLUSIVE_INCLUSIVE 前后都包括,在指定范围前后插入新字符,都会应用新样式
SPAN_EXCLUSIVE_EXCLUSIVE 前后都不包括,在指定范围前后插入新字符,两端样式无变化
SPAN_INCLUSIVE_EXCLUSIVE 前面包括,后面不包括
SPAN_EXCLUSIVE_INCLUSIVE 后面包括,前面不包括

通常在insert方式才生效,平时不生效。

2.常用span类

常用类 说明
BackgroundColorSpan 背景色样式,显然可以用来设定文本的背景色
ForegroundColorSpan 字体颜色样式,用于改变字体颜色
StyleSpan 主要由正常、粗体、斜体和同时加粗倾斜四种样式
TypefaceSpan 设置不同的字体
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默认对其方式有两种:ALIGN_BOTTOM及ALIGN_BASELINE。很可惜我们平常用的居中对其的方式没有,不过可以通过自定义实现,后续会在开源出来。

4.效果

五、HTML显示

一般显示HTML内容有两种方式:

现在大多数都用WebView的方式。但是并不是所有的场景下都适合使用 WebView 来显示 HTML 内容,例如,如果应用要显示的内容只是一部分 HTML 片段,就可以利用 TextView 来进行显示,并且效率较高。

由于这种方式不太常用,就不深入介绍,里面可以实现的效果还是很好的。

1.简介

Android 中的 TextView 组件常用于显示文本内容,其实它也可以显示 HTML 的内容。

简单来讲,这就需要先把 HTML 的内容以字符串的形式获取后,经过 android.text.Html.fromHtml()转化成 Spanned 的格式,然后将其传递到 TextView 的 setText()方法中,这样就可以在 TextView 中显示 HTML 页面的内容了。

需要注意的是,并不是所有的 HTML 标签在 TextView 中都是支持的,且官方文档并没有明确的说明支持 HTML 标签列表,通过查看 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 内容,要显示的这段 HTML 内容即包含超链接内容,也包含有图片。

2.使用

fromHtml方法

fromHtml(String source, ImageGetter imageGetter,TagHandler tagHandler)

继承ImageGetter

继承于 ImageGetter,重写 getDrawable (String source) 方法。通过异步操作,读取本地/网络资源,获得drawable对象。

继承TagHandler

继承于 TagHandler,重写了 handleTag()方法。为了支持更多的标签,例如为了支持<ul><ol><dd>和<li>标签,这四个标签是在 formHtml()方法中本身是不支持。

如果开发者认为安卓 TagHandler 提供的默认标签解析已经够用,直接在 fromHtml()方法中第三个参数的地方填写 null 既可。

最后,通过 formHtml()方法将 HTML 内容转化为可供显示的 SpannableString,将 SpannableString 通过 setText 方法放入 TextView 中,就可以显示图文并茂的内容了。

用户交互

formHtml()方法已经将 HTML 内容中的超链接和图片转义成为 UrlSpan 和 ImageSpan,进而在 TextView 中完成显示。但是此时是没有任何用户交互的,用户只能看到 HTML 的内容,下面介绍如何添加用户交互功能。

要完成用户交互,这里我们需要在 TextView 中还需要调用textView.setMovementMethod()方法。

Android 提供了 LinkMovementMethod 类以实现了对于文本内容中超链接的遍历,并且支持对于超链接的点击事件。

所以只要在添加下面一行代码,就可以使点击 UrlSpan 能够触发打开链接的功能。

textView.setMovementMethod(LinkMovementMethod.getInstance())

如果想要更多的用户交互效果,可以自定义LinkMovementMethod 类,重写onTouchEvent方法来实现。

3.效果

点击图片,跳转到图片详情页。

关于HTML显示这部分,没做具体实现。具体可以看:灵活高效的在 Android Native App 开发中显示 HTML 内容,里面有具体源码可以下载,HTML部分内容也是参考该篇文章完成的。
开源库:html-textview

六、总结

以上就是关于图文混排的一些解决方案,相信通过这些了解,对于工作中的实际场景的使用大家会有适当的解决方案。由于实际应用较少,所以认识较为浅显,可能有些地方描述不当,后期会考虑封装个解决图文混排的工具类,加深下理解。

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

点击链接加入群聊【Android移动架构总群】:加入群聊

资料大全
上一篇下一篇

猜你喜欢

热点阅读