有的时候可能想在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等指定特殊字符串与点击事件 ,实现起来应该是没有困难的。因此笔者不再赘述了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Android实现可点击展开的TextView,包括了Android实现可点击展开的TextView的使用技巧和注意事项,需要的朋友参考一下 概述 Android开发过程中,经常遇到 Textview 展示不完全的情况。 遇到此情况,通常的处理是: 方案一 Textview 添加 android:ellipsize 属性,让展示不完的部分使用省略号代替。 方案二 Textview 采
我无法在自定义适配器的<code>getView() 我已经尝试了以下解决方案,但它不适合我: 解决方案一 解决方案二 解决方案三 列表视图. xml文件: 下面是我的keep_resing xml文件: 下面是我的适配器代码: 问题是,我无法将文本视图文本更改为“测试”。 注意:如果我通过执行“< code > holder . hello text . gettext()来查看Toast中的值
本文向大家介绍Android自定义可左右滑动和点击的折线图,包括了Android自定义可左右滑动和点击的折线图的使用技巧和注意事项,需要的朋友参考一下 前言 前几天有小盆友让我写一个折线图,可以点击,可以左右滑动。对于折线肯定有很多项目都使用过,所以网上肯定也有很多demo,像AndroidChart、HelloChart之类的,功能相当丰富,效果也很赞,但是太重了,其他的小demo
问题内容: 所以我有一个自定义ListView对象。列表项具有两个彼此叠放的textview,以及一个水平进度条,在我实际执行某项操作之前,我一直希望保持水平状态。最右边是一个复选框,仅在用户需要将更新下载到他们的数据库时才显示。通过将可见性设置为Visibility.GONE禁用复选框时,我可以单击列表项。当该复选框可见时,我无法单击列表中除复选框以外的任何内容。我已经进行了一些搜索,但没有找到
带问题的我的地图截图 向Taskmanager致以亲切的问候
本文向大家介绍Android自定义带拼音音调Textview,包括了Android自定义带拼音音调Textview的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android自定义带拼音音调Textview的具体代码,供大家参考,具体内容如下 1.拼音textview,简单的为把拼音数组和汉字数组结合在一起多行显示 2.汉字转拼音使用 implementation ‘com.bel