TextView + Spanned 实现图文混排以及点击交互

2,450 阅读3分钟

最近要实现图文混排的需求,webview过大,所以想到了用SpannableStringBuilder来实现。 不过参考了大量国内文章,大多数是教你如何实现图文混排,并没有提及图片点击交互的。有翻阅了一些国外文章,说的也不是很详细,于是花费时间鼓捣了一下,最终实现了TextView图文混排,加点击交互的效果,在这里给大家分享下以免后来者在此处浪费过多时间。

主要用到的有Spanned ClickSpan ImageSpan ImagerGetter Html 。
先看一下效果图:
查看图片

我把它封装成了一个控件,使用的时候只要将它放到xml布局
下载地址:github.com/githubwing/…




  

,然后
  RichTextView richTextView = (RichTextView) findViewById(R.id.richTextView)
    richTextView.setHtml(mTxt,1000,800)
    richTextView.setOnImageClickListener(new RichTextView.ImageClickListener() {
      @Override public void onImageClick(String imageUrl, String[] imageUrls, int position) {
        Toast.makeText(MainActivity.this, "imageUrl :"+imageUrl+"\nimage size:"+imageUrls.length+"\n position:"+position, Toast.LENGTH_SHORT).show()
      }
    })

实现思路

由于后台是传来的html,所以可以借助系统类Html来解析生成Spanned,再将SpannedString转换为ClickSpan,最终实现图文混排+图片交互效果。

后台先传来一段html,如下:

String mTxt =
      "

\r\n\t比腾讯还土豪 传《阴阳师》项目组发60个月工资奖金\r\n

\r\n

\r\n\t  今日下午一则关于网易《阴阳师》项目组员工发60个月工资的奖金忽然在整个游戏圈流传,而以网易游戏平均10000以上的薪资水平来算,《阴阳师》项目组成员的奖金将达到60万元以上。" + "\"上证指数\"在游戏公司项目组发奖金较为平常,不过能够达到60个月工资的也就此前盛传的腾讯LOL项目组曾经打到过,包括几年之前被业界津津乐道的CF项目组都未曾有过这么高的规格。根据多家网站的数据和行业平均水平,网易游戏的平均薪资应该不会低于10000,这笔奖金的总额度可能创游戏行业有史以来最高。" + "\r\n

\r\n

\r\n\t
\r\n
\r\n

\r\n

\r\n\t\"上证指数\"《阴阳师》是网易自研的3D和风卡牌RPG手游,同时该作也是一款二次元向手游,游戏9月2正式上架App Store,9月9日开始全平台公测,自上架以来该作就开始了传奇的冲榜之旅,到今天已经高居畅销榜第二名,仅次于长期包揽第一的同门师兄《梦幻西游》。\n" + "\n" + "\"上证指数\""; 之后利用Html.form()生成Spanned

stringBuilder = (SpannableStringBuilder) Html.fromHtml(source,
        new GlideImageGetter(mContext, Glide.with(mContext), this, false, width, height), null);

注意这里的第二个参数,是一个ImageGetter类型的接口,这里直接拿了Glide作者开发的Imagegetter来使用,他的作用是在spanned中加载图片。

国内的文章大多介绍到这里,实现了图文混排。。。然后就没有然后了。。可是尼玛我想点击放大啊有没有。。 莫急,接下来就告诉你们,如何点击交互。

其实就是将Spanned转换为clickspan,


mImageSpans = stringBuilder.getSpans(0, stringBuilder.length(), ImageSpan.class);

     
    mImageUrls = new String[mImageSpans.length];
    for (int i = 0; i < mImageSpans.length; i++) {
      mImageUrls[i] = mImageSpans[i].getSource();
    }
    for (int i = 0; i < mImageSpans.length; i++) {

        
      int start = stringBuilder.getSpanStart(mImageSpans[i]);
      int end = stringBuilder.getSpanEnd(mImageSpans[i]);
      final int finalI = i;

      
      stringBuilder.setSpan(new ClickableSpan() {
        @Override public void onClick(View widget) {
          if (mImageClickListener != null) {
            mImageClickListener.onImageClick(mImageUrls[finalI], mImageUrls, finalI);
          }
        }
      }, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

嘛。。理论上这样就可以了,可是事实上,你会发现,点击图片根本没鸟反应!!!!!然后我有鼓捣了一会。。发现需要加上一句,才可以。


    setMovementMethod(LinkMovementMethod.getInstance());