android图文混排

背景

最近我们的产品来了个新的模块,给学生做题提高成绩的。需求如下:

  1. 支持单选、多选、填空题
  2. 支持图片文字混排
  3. 输入框有交互,排版精致美观
  4. 为了体验优化,不能使用网页实现效果

思路分析

我们的图文混排控件继承自TextView,重写了关键的测量onMeasure和绘制onDraw步骤
测量决定了混排里的元素的位置、尺寸;
绘制决定了如何去渲染这些元素(以及通知输入框位置)

1:图片文字混排

系统的TextView通过ImageGetter就可以原生实现对文本img标签的支持,从而达到图文混排的效果。
具体实现步骤请参考Github上的一个库https://github.com/zzhoujay/RichText

2:输入框混排

如何实现一个自己的TextView,请参考此篇博客http://blog.csdn.net/yellowcath/article/details/27527275

下面是我具体的实现步骤,请在步骤1图文混排源码基础上进行阅读。

最后的UI结构应该是这样子的,用输入框盖在透明的占位图上,达到了输入框混排的效果。

做题控件树

如果是列表里展示结果,不涉及输入框的。那就只有一个图文混排控件,把输入框转换成下划线____即可

2.0:根据题目答案数量,生成对应数量的输入框,添加到容器中,设置为不可见

2.1:题目中的输入框标记,通过正则表达式使用图片Img标签代替,src设置为:Input标签+输入框对应答案ID+该输入框对应答案文字长度

2.2:在ImageGetter中,发现当前图片包含Input标签,则使用一个透明的占位图代替,宽度为画笔的文本尺寸*答案长度

2.3:参考本步骤开始给出的代码地址,稍微加工下就可以拿来实现自己的TextView,在onDraw事件里,就能获取当前的x、y值。

2.4:在onDraw事件里,遇到当前绘制的Span是图片类型,且src包含Input标签的,获取当前的高度和左边距,通过下面代码获取图片的宽度。imgSpan.getDrawable().getBounds().width()

2.5:用步骤4取到的数据,设置MarginLeftMarginTop,还有宽度,通过输入框对应答案ID来找到2.0对应的输入框,刷新其位置和宽度

输入框排版大体流程

最终实现的效果如如下,满足产品需求

效果图1
效果图2

FAQ

下面是一些网友的提问

1 问题:效果图里,文字垂直居中对齐,怎么做到的

回答:
原生TextView是底部对齐的,我们自己实现的图文混排是可以自由定制垂直对齐方式的,参考我给出的第二个博客地址,他里面会记录每一行的行高,然后在绘制的时候,判断当前行高是否大于标准行高(我们填空题或者选择题都会有一个初始行高。)

如果当前行高>默认行高,则说明此行有大图,文本垂直居中=当前高度+(行高-文本高度)/2;

如果当前行高==默认行高,判断图片的高度如果小于默认行高,则图片垂直居中=当前高度+(行高-图片高度)/2;

2 请问返回的数据有处理不了的标签怎么处理,还有怎么实现如果返回的图片宽度大于一屏不被截图的问题呢?

回答:
1:标签和服务端沟通好,只返回有用的标签。一些数学符号用png图片代替。
2:Html.ImageGetter,在请求返回Bitmap的时,对Bitmap的宽度进行判断(bitmap.getWidth()),如果超过最大宽度,则使用最大宽度,同时拿到缩放比率,对高度进行等比处理。

3 填空输入功能看了您的文章还是不太明白,请问您三个关于输入框排版的问题。

1、输入框怎么拿到input位置。
2、输入框怎么刷新位置。
3、输入框怎么与文字对齐居中。

回答:
第一个问题输入框怎么拿到input位置。
1:input我们实际上也是转换成一个图片标签<img src="input_A">
2:参考http://blog.csdn.net/yellowcath/article/details/27527275如何实现自定义TextView;里面ondraw的时候,判断当前是个imageSpan,并且srcinput_A
3:满足2,则判定,该image标签是个输入框标签。如果你仔细看过2步骤的博客;则知道自定义TextView是逐行绘制标签的,我们在绘制的时候,是可以拿到当前的x和y的。

第二个问题输入框怎么刷新位置。
还记得一步骤的src里面的input_A吗?这是我们自定义的标签,第二个标签则是input_B。以此类推
input_A 我们对应创建一个输入框A,放进一个hashMap
逐行绘制的时候,我们拿到x、y,则更新该输入框的x、y就好了。

第三个问题输入框怎么与文字对齐居中。
参考问题2给出的答案

补充

这个图文混排模块,我在17年的时候就已经完成上线了,最早发布在博客园https://www.cnblogs.com/kimmy/p/5027299.html
到今天3年过去,期间的迭代主要围绕着渲染性能、各种格式文本支持,标签(<u><b><i>)嵌套扩展性等迭代,主体测量、绘制流程大体上就是文中所述。

安卓原生的Html.fromHtml在处理一些标签的时候,需要额外预处理下比如

   * 
     * <p>
     * 将不是html标签的< 替换成&lt; 不然{@link android.text.Html#fromHtml(String)}会丢失,比如下面数据只有a,  "a<b 巴拉巴拉";
     * 把不是引号里的空格 替换成&nbsp;不然{@link android.text.Html#fromHtml(String)}会将多个空格合并成一个
     * 把不是引号里的\n 替换成 <br/>;不然{@link android.text.Html#fromHtml(String)}处理后,课后堂堂清渲染引擎识别不了换行符号
     * <p>
     * 输入:<b>c<d </br>(   ) \n
     * 输出:&lt;b>c&lt;d&nbsp;</br>(&nbsp;&nbsp;&nbsp;)<br/>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271