当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义可点击的ImageSpan并在TextView中内置View

Android自定义可点击的ImageSpan并在TextView中内置View

2019年07月24日  | 移动技术网移动技术  | 我要评论

有的时候可能想在textview中添加一些图片,比如下图,发短信输入联系人时,要把联系人号码换成一个图片,但这个图片无法用固定的某张图,而是根据内容进行定制的,这更像一个view。

 

当然,如果你不是view而是固定的图片,比如发信息时用表情图片替代特殊符号,那么实现起来会更加简单。又或许,你希望这个图片是可点击的。这里,笔者要介绍的就是怎么用一个自定义的imagespan来实现在文本里插入可点击的图片或view。

在此之前,如果你还不了解spannablestring.setspan(),不了解linkmovementmethod是什么,建议先看下笔者的解析textview中的url等指定特殊字符串与点击事件

首先,因为imagespan没有继承clickablespan,因此没有 onclick()方法。所以我写了个clickableimagespan 。 

public abstract class clickableimagespan extends imagespan {
 public clickableimagespan(drawable b) {
  super(b);
 }

 public abstract void onclick(view view);
}

同时,我们发现google提供的linkmovementmethod只会执行clickablespan的onclick()方法.下面是linkmovementmethod的ontouchevent()的源码。这个方法是在我们点击spanned的时候响应。

public boolean ontouchevent(textview widget, spannable buffer,
        motionevent event) {
  int action = event.getaction();

  if (action == motionevent.action_up ||
   action == motionevent.action_down) {
   int x = (int) event.getx();
   int y = (int) event.gety();

   x -= widget.gettotalpaddingleft();
   y -= widget.gettotalpaddingtop();

   x += widget.getscrollx();
   y += widget.getscrolly();

   layout layout = widget.getlayout();
   int line = layout.getlineforvertical(y);
   int off = layout.getoffsetforhorizontal(line, x);

   clickablespan[] link = buffer.getspans(off, off, clickablespan.class);

   if (link.length != 0) {
    if (action == motionevent.action_up) {
     link[0].onclick(widget);
    } else if (action == motionevent.action_down) {
     selection.setselection(buffer,
           buffer.getspanstart(link[0]),
           buffer.getspanend(link[0]));
    }

    return true;
   } else {
    selection.removeselection(buffer);
   }
  }

  return super.ontouchevent(widget, buffer, event);
 }

发现这个方法其实就是通过坐标找到相应的span。然后,当link数组不为空时,将会得到span并执行他的onclick()方法。这里我们注意到了这一句代码 

clickablespan[] link = buffer.getspans(off, off, clickablespan.class); 

这说明该方法只获得了clickablespan,因为如果我们直接使用系统的linkmovementmethod类,是无法让imagespan响应点击事件的。。因为我们知道,imagespan没有继承clickablespan。所以,笔者写了一个clickablemovementmethod

public class clickablemovementmethod extends linkmovementmethod {

 private static clickablemovementmethod sinstance;

 public static clickablemovementmethod getinstance() {
  if (sinstance == null) {
   sinstance = new clickablemovementmethod();
  }
  return sinstance;
 }

 public boolean ontouchevent(textview widget, spannable buffer,
        motionevent event) {
  int action = event.getaction();

  if (action == motionevent.action_up ||
    action == motionevent.action_down) {
   int x = (int) event.getx();
   int y = (int) event.gety();

   x -= widget.gettotalpaddingleft();
   y -= widget.gettotalpaddingtop();

   x += widget.getscrollx();
   y += widget.getscrolly();

   layout layout = widget.getlayout();
   int line = layout.getlineforvertical(y);
   int off = layout.getoffsetforhorizontal(line, x);

   clickablespan[] link = buffer.getspans(off, off, clickablespan.class);
   clickableimagespan[] imagespans = buffer.getspans(off, off, clickableimagespan.class);

   if (link.length != 0) {
    if (action == motionevent.action_up) {
     link[0].onclick(widget);
    } else if (action == motionevent.action_down) {
     selection.setselection(buffer,
       buffer.getspanstart(link[0]),
       buffer.getspanend(link[0]));
    }

    return true;
   } else if (imagespans.length != 0) {
    if (action == motionevent.action_up) {
     imagespans[0].onclick(widget);
    } else if (action == motionevent.action_down) {
     selection.setselection(buffer,
       buffer.getspanstart(imagespans[0]),
       buffer.getspanend(imagespans[0]));
    }

    return true;
   } else {
    selection.removeselection(buffer);
   }
  }

  return false;
 }
}

只是做了很小的改动,这样,这个类既可以支持clickablespan也可以支持我们自己写的clickableimagespan。

到此为止,一个可点击的imagespan就完成了。剩下的步骤就跟实现文字样式的方式一样,首先new一个spannablestring传入文本,然后找到你需要放置imagespan的位置(一般使用正则表达式),接着new一个clickableimagespan传入图片,通过spannablestring的setspan()方法传入clickableimagespan对象。最后别忘了textview调用setmovementmethod时,传入的是我们的clickablemovementmethod.getinstance()方法。具体代码实现参照文字样式那边的,稍作修改即可。具体的笔者不再贴这部分的代码了。

那么,如果我们不是传一个简单的图片,而是需要显示一个定制的view,应该怎么做呢。其实只要把view转化成drawable就好,下面是主要的实现代码:

 private bitmapdrawable createdrawble(context ctx, string content) {
 view view = layoutinflater.from(ctx).inflate(r.layout.viewt, null);
 ((textview) view.findviewbyid(r.id.tv_content)).settext(content);
 int spec = view.measurespec.makemeasurespec(0, view.measurespec.unspecified);
 view.measure(spec, spec);
 view.layout(0, 0, view.getmeasuredwidth(), view.getmeasuredheight());
 bitmap b = bitmap.createbitmap(view.getmeasuredwidth(), view.getmeasuredheight(), bitmap.config.argb_8888);
 canvas c = new canvas(b);
 c.translate(-view.getscrollx(), -view.getscrolly());
 view.draw(c);
 view.setdrawingcacheenabled(true);
 bitmap cachebmp = view.getdrawingcache();
 bitmap viewbmp = cachebmp.copy(bitmap.config.argb_8888, true);
 view.destroydrawingcache();
 return new bitmapdrawable(ctx.getresources(), viewbmp);
 }

 public void filter(spannable sp) {
 /**
  .....此处省略.
 **/
 bitmapdrawable bd = createdrawble(tv.getcontext(), sp.tostring); bd.setbounds(0, 0, bd.getintrinsicwidth(), bd.getintrinsicheight());
 myclickableimagespan span = new myclickableimagespan(bd,text);
 sp.setspan(span, start, end, spanned.span_exclusive_exclusive);
 }

createdrawble()方法是通过view的getdrawingcache()方法将一个view转化成bitmap,然后在获得bitmapdrawable 后别忘了调用setbounds(),这个方法是决定图片的大小,如果不设置,那么图片长宽都为0! 当然,你如果嫌显示的效果太大或太小,也可以通过这个方法调整图片大小。其他步骤相信大家看过笔者的 解析textview中的url等指定特殊字符串与点击事件 ,实现起来应该是没有困难的。因此笔者不再赘述了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网