Android自定義可點(diǎn)擊的ImageSpan并在TextView中內(nèi)置View
有的時(shí)候可能想在TextView中添加一些圖片,比如下圖,發(fā)短信輸入聯(lián)系人時(shí),要把聯(lián)系人號(hào)碼換成一個(gè)圖片,但這個(gè)圖片無法用固定的某張圖,而是根據(jù)內(nèi)容進(jìn)行定制的,這更像一個(gè)view。
當(dāng)然,如果你不是view而是固定的圖片,比如發(fā)信息時(shí)用表情圖片替代特殊符號(hào),那么實(shí)現(xiàn)起來會(huì)更加簡(jiǎn)單。又或許,你希望這個(gè)圖片是可點(diǎn)擊的。這里,筆者要介紹的就是怎么用一個(gè)自定義的ImageSpan來實(shí)現(xiàn)在文本里插入可點(diǎn)擊的圖片或View。
在此之前,如果你還不了解SpannableString.setSpan(),不了解LinkMovementMethod是什么,建議先看下筆者的解析TextView中的URL等指定特殊字符串與點(diǎn)擊事件
首先,因?yàn)镮mageSpan沒有繼承ClickableSpan,因此沒有 onClick()方法。所以我寫了個(gè)ClickableImageSpan 。
public abstract class ClickableImageSpan extends ImageSpan {
public ClickableImageSpan(Drawable b) {
super(b);
}
public abstract void onClick(View view);
}
同時(shí),我們發(fā)現(xiàn)google提供的LinkMovementMethod只會(huì)執(zhí)行ClickableSpan的onClick()方法.下面是LinkMovementMethod的onTouchEvent()的源碼。這個(gè)方法是在我們點(diǎn)擊Spanned的時(shí)候響應(yīng)。
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);
}
發(fā)現(xiàn)這個(gè)方法其實(shí)就是通過坐標(biāo)找到相應(yīng)的Span。然后,當(dāng)link數(shù)組不為空時(shí),將會(huì)得到span并執(zhí)行他的onClick()方法。這里我們注意到了這一句代碼
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
這說明該方法只獲得了ClickableSpan,因?yàn)槿绻覀冎苯邮褂孟到y(tǒng)的LinkMovementMethod類,是無法讓ImageSpan響應(yīng)點(diǎn)擊事件的。。因?yàn)槲覀冎溃琁mageSpan沒有繼承ClickableSpan。所以,筆者寫了一個(gè)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;
}
}
只是做了很小的改動(dòng),這樣,這個(gè)類既可以支持ClickableSpan也可以支持我們自己寫的ClickableImageSpan。
到此為止,一個(gè)可點(diǎn)擊的ImageSpan就完成了。剩下的步驟就跟實(shí)現(xiàn)文字樣式的方式一樣,首先new一個(gè)SpannableString傳入文本,然后找到你需要放置ImageSpan的位置(一般使用正則表達(dá)式),接著new一個(gè)ClickableImageSpan傳入圖片,通過SpannableString的setSpan()方法傳入ClickableImageSpan對(duì)象。最后別忘了TextView調(diào)用setMovementMethod時(shí),傳入的是我們的ClickableMovementMethod.getInstance()方法。具體代碼實(shí)現(xiàn)參照文字樣式那邊的,稍作修改即可。具體的筆者不再貼這部分的代碼了。
那么,如果我們不是傳一個(gè)簡(jiǎn)單的圖片,而是需要顯示一個(gè)定制的View,應(yīng)該怎么做呢。其實(shí)只要把View轉(zhuǎn)化成Drawable就好,下面是主要的實(shí)現(xiàn)代碼:
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()方法將一個(gè)View轉(zhuǎn)化成BItmap,然后在獲得BitmapDrawable 后別忘了調(diào)用setBounds(),這個(gè)方法是決定圖片的大小,如果不設(shè)置,那么圖片長(zhǎng)寬都為0! 當(dāng)然,你如果嫌顯示的效果太大或太小,也可以通過這個(gè)方法調(diào)整圖片大小。其他步驟相信大家看過筆者的 解析TextView中的URL等指定特殊字符串與點(diǎn)擊事件 ,實(shí)現(xiàn)起來應(yīng)該是沒有困難的。因此筆者不再贅述了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android中TextView實(shí)現(xiàn)超過固定行數(shù)顯示“...展開全部”
- Android中TextView實(shí)現(xiàn)分段顯示不同顏色的字符串
- Android實(shí)現(xiàn)可點(diǎn)擊展開的TextView
- android使用Textview實(shí)現(xiàn)伸縮效果
- Android實(shí)現(xiàn)可以展開的TextView
- Android TextView實(shí)現(xiàn)詞組高亮的示例代碼
- Android中實(shí)現(xiàn)詞組高亮TextView方法示例
- Android Textview實(shí)現(xiàn)顏色漸變滾動(dòng)效果
- Android開發(fā)自定義TextView省略號(hào)樣式的方法
- Android中TextView實(shí)現(xiàn)部分文字可點(diǎn)擊跳轉(zhuǎn)
- Android中TextView局部變色功能實(shí)現(xiàn)
相關(guān)文章
android 通過向viewpage中添加listview來完成滑動(dòng)效果(類似于qq滑動(dòng)界面)
android 通過向viewpage中添加listview來完成滑動(dòng)效果(類似于qq滑動(dòng)界面),需要的朋友可以參考一下2013-05-05
Android編程之菜單Menu的創(chuàng)建方法示例
這篇文章主要介紹了Android編程之菜單Menu的創(chuàng)建方法,結(jié)合實(shí)例形式分析了Android菜單Menu的布局、響應(yīng)及功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08
Android?Studio實(shí)現(xiàn)簡(jiǎn)易計(jì)算器App?(Java語言版)
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡(jiǎn)易計(jì)算器App,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Android應(yīng)用中ListView利用OnScrollListener分頁(yè)加載數(shù)據(jù)
這篇文章主要介紹了Android應(yīng)用中ListView利用OnScrollListener分頁(yè)加載數(shù)據(jù)的方法,包括對(duì)OnScrollListener事件順序次數(shù)的分析,需要的朋友可以參考下2016-03-03
android實(shí)現(xiàn)點(diǎn)擊按鈕切換不同的fragment布局
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)點(diǎn)擊按鈕切換不同的fragment布局,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁(yè)
這篇文章主要為大家詳細(xì)介紹了Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁(yè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
Android跳轉(zhuǎn)三方應(yīng)用實(shí)例代碼
大家好,本篇文章主要講的是Android跳轉(zhuǎn)三方應(yīng)用實(shí)例代碼,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
Android Dialog對(duì)話框?qū)嵗a講解
本文通過實(shí)例代碼給大家介紹了Android Dialog對(duì)話框的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08

