自訂可點擊的ImageSpan並在TextView中內建“View“,imagespantextview

來源:互聯網
上載者:User

自訂可點擊的ImageSpan並在TextView中內建“View“,imagespantextview

有的時候可能想在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的位置(一般使用Regex),接著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等指定特殊字元串與點擊事件,實現起來應該是沒有困難的。因此筆者不再贅述了。

 

有任何問題或更好的見解可以留言,互相學習!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.