最近要实现图文混排的需求,webview过大,所以想到了用SpannableStringBuilder来实现。 不过参考了大量国内文章,大多数是教你如何实现图文混排,并没有提及图片点击交互的。有翻阅了一些国外文章,说的也不是很详细,于是花费时间鼓捣了一下,最终实现了TextView图文混排,加点击交互的效果,在这里给大家分享下以免后来者在此处浪费过多时间。
主要用到的有Spanned ClickSpan ImageSpan ImagerGetter Html 。
先看一下效果图:
我把它封装成了一个控件,使用的时候只要将它放到xml布局
下载地址:https://github.com/githubwing/RichTextView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span> <span class="hljs-tag"><<span class="hljs-title">RelativeLayout </span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span> <span class="hljs-attribute">xmlns:tools</span>=<span class="hljs-value">"http://schemas.android.com/tools"</span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/activity_main"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:paddingBottom</span>=<span class="hljs-value">"@dimen/activity_vertical_margin"</span> <span class="hljs-attribute">android:paddingLeft</span>=<span class="hljs-value">"@dimen/activity_horizontal_margin"</span> <span class="hljs-attribute">android:paddingRight</span>=<span class="hljs-value">"@dimen/activity_horizontal_margin"</span> <span class="hljs-attribute">android:paddingTop</span>=<span class="hljs-value">"@dimen/activity_vertical_margin"</span> <span class="hljs-attribute">tools:context</span>=<span class="hljs-value">"com.wingsofts.richtextview.MainActivity"</span> ></span> <span class="hljs-tag"><<span class="hljs-title">com.wingsofts.richtextview.RichTextView </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/richTextView"</span> <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span> <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">RelativeLayout</span>></span> </code>,然后 |
1 2 3 4 5 6 7 |
RichTextView richTextView = (RichTextView) findViewById(R<span class="hljs-preprocessor">.id</span><span class="hljs-preprocessor">.richTextView</span>)<span class="hljs-comment">;</span> richTextView<span class="hljs-preprocessor">.setHtml</span>(mTxt,<span class="hljs-number">1000</span>,<span class="hljs-number">800</span>)<span class="hljs-comment">;</span> richTextView<span class="hljs-preprocessor">.setOnImageClickListener</span>(new RichTextView<span class="hljs-preprocessor">.ImageClickListener</span>() { @Override public void onImageClick(String imageUrl, String[] imageUrls, int position) { Toast<span class="hljs-preprocessor">.makeText</span>(MainActivity<span class="hljs-preprocessor">.this</span>, <span class="hljs-string">"imageUrl :"</span>+imageUrl+<span class="hljs-string">"\nimage size:"</span>+imageUrls<span class="hljs-preprocessor">.length</span>+<span class="hljs-string">"\n position:"</span>+position, Toast<span class="hljs-preprocessor">.LENGTH</span>_SHORT)<span class="hljs-preprocessor">.show</span>()<span class="hljs-comment">;</span> } })<span class="hljs-comment">;</span> |
实现思路
由于后台是传来的html,所以可以借助系统类Html来解析生成Spanned,再将SpannedString转换为ClickSpan,最终实现图文混排+图片交互效果。
后台先传来一段html,如下:
1 2 3 4 5 6 7 |
String mTxt = "<p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><span class="hljs-command">\t</span><span style=<span class="hljs-command">\"</span>font-size:16px;<span class="hljs-command">\"</span>><strong>比腾讯还土豪 传《阴阳师》项目组发60个月工资奖金</strong></span><span class="hljs-command">\r</span><span class="hljs-command">\n</span></p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><span class="hljs-command">\t</span><span style=<span class="hljs-command">\"</span>font-size:16px;<span class="hljs-command">\"</span>> 今日下午一则关于网易《阴阳师》项目组员工发60个月工资的奖金忽然在整个游戏圈流传,而以网易游戏平均10000以上的薪资水平来算,《阴阳师》项目组成员的奖金将达到60万元以上。" + "<img src=<span class="hljs-command">\"</span>http://p2.pstatp.com/large/e220006a85a0b689eb8<span class="hljs-command">\"</span> width=<span class="hljs-command">\"</span>520<span class="hljs-command">\"</span> height=<span class="hljs-command">\"</span>216<span class="hljs-command">\"</span> title=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> alt=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> />在游戏公司项目组发奖金较为平常,不过能够达到60个月工资的也就此前盛传的腾讯LOL项目组曾经打到过,包括几年之前被业界津津乐道的CF项目组都未曾有过这么高的规格。根据多家网站的数据和行业平均水平,网易游戏的平均薪资应该不会低于10000,这笔奖金的总额度可能创游戏行业有史以来最高。" + "</span><span class="hljs-command">\r</span><span class="hljs-command">\n</span></p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><span class="hljs-command">\t</span><span style=<span class="hljs-command">\"</span>font-size:16px;<span class="hljs-command">\"</span>><br /><span class="hljs-command">\r</span><span class="hljs-command">\n</span></span><span class="hljs-command">\r</span><span class="hljs-command">\n</span></p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><p><span class="hljs-command">\r</span><span class="hljs-command">\n</span><span class="hljs-command">\t</span><span style=<span class="hljs-command">\"</span>font-size:16px;<span class="hljs-command">\"</span>><img src=<span class="hljs-command">\"</span>http://p3.pstatp.com/large/e1d000f89d603327470<span class="hljs-command">\"</span> width=<span class="hljs-command">\"</span>520<span class="hljs-command">\"</span> height=<span class="hljs-command">\"</span>216<span class="hljs-command">\"</span> title=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> alt=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> />《阴阳师》是网易自研的3D和风卡牌RPG手游,同时该作也是一款二次元向手游,游戏9月2正式上架App Store,9月9日开始全平台公测,自上架以来该作就开始了传奇的冲榜之旅,到今天已经高居畅销榜第二名,仅次于长期包揽第一的同门师兄《梦幻西游》。<span class="hljs-command">\n</span>" + "<span class="hljs-command">\n</span>" + "<img src=<span class="hljs-command">\"</span>http://p3.pstatp.com/large/e21000f51e83cb9b1c9<span class="hljs-command">\"</span> width=<span class="hljs-command">\"</span>520<span class="hljs-command">\"</span> height=<span class="hljs-command">\"</span>216<span class="hljs-command">\"</span> title=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> alt=<span class="hljs-command">\"</span>上证指数<span class="hljs-command">\"</span> />"; </code>之后利用Html.form()生成Spanned |
1 2 3 |
stringBuilder = (SpannableStringBuilder) Html.fromHtml(source, <span class="hljs-keyword">new</span> GlideImageGetter(mContext, Glide.<span class="hljs-keyword">with</span>(mContext), <span class="hljs-keyword">this</span>, <span class="hljs-literal">false</span>, width, height), <span class="hljs-literal">null</span>); |
注意这里的第二个参数,是一个ImageGetter类型的接口,这里直接拿了Glide作者开发的Imagegetter来使用,他的作用是在spanned中加载图片。
国内的文章大多介绍到这里,实现了图文混排。。。然后就没有然后了。。可是尼玛我想点击放大啊有没有。。 莫急,接下来就告诉你们,如何点击交互。
其实就是将Spanned转换为clickspan,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<span class="hljs-comment">//从stringBuilder中读取图片</span> mImageSpans = stringBuilder.getSpans(<span class="hljs-number">0</span>, stringBuilder.length(), ImageSpan.class); <span class="hljs-comment">//过滤出整个textView的所有图片</span> mImageUrls = <span class="hljs-keyword">new</span> String[mImageSpans.length]; <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < mImageSpans.length; i++) { mImageUrls[i] = mImageSpans[i].getSource(); } <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < mImageSpans.length; i++) { <span class="hljs-comment">//获取图片span的起尾</span> <span class="hljs-keyword">int</span> start = stringBuilder.getSpanStart(mImageSpans[i]); <span class="hljs-keyword">int</span> end = stringBuilder.getSpanEnd(mImageSpans[i]); <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> finalI = i; <span class="hljs-comment">//将span转化为clickspan</span> stringBuilder.setSpan(<span class="hljs-keyword">new</span> ClickableSpan() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View widget) { <span class="hljs-keyword">if</span> (mImageClickListener != <span class="hljs-keyword">null</span>) { mImageClickListener.onImageClick(mImageUrls[finalI], mImageUrls, finalI); } } }, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } |
嘛。。理论上这样就可以了,可是事实上,你会发现,点击图片根本没鸟反应!!!!!然后我有鼓捣了一会。。发现需要加上一句,才可以。
1 2 |
<span class="hljs-function">setMovementMethod(LinkMovementMethod.<span class="hljs-function">getInstance()</span>)</span>; |
请问一下,GlideImageGetter这个类是在哪找到的?
这个是在gayhub找到啊- –
楼主用的是什么录屏软件呀