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

Android自定义可点击的ImageSpan并在TextView中内置,第1张

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

有的时候可能想在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,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,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,ClickableSpan.class);      ClickableImageSpan[] imageSpans = buffer.getSpans(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.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,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,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等指定特殊字符串与点击事件 ,实现起来应该是没有困难的。因此笔者不再赘述了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android自定义可点击的ImageSpan并在TextView中内置全部内容,希望文章能够帮你解决Android自定义可点击的ImageSpan并在TextView中内置所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1143622.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存