2014年2月11日 星期二

Android 開發 (二十六) handle hyperlink in textView(二)

handle hyperlink in textView(一) 中有提到如何使 textview 能夠處理url 使之能夠被點擊。
但是如果僅使用那邊的寫法,當將這個textview放到 listview內會造成 itemclick無法被點擊的問題。

為何會造成這個問題?

由於設定 setmovementmethod會同時 
  • setFocusable(true);
  • setClickable(true);
  • setLongClickable(true);
簡單的說就是 Event 都被 Textview處理掉了,所以listview拿不到itemclick event。
所以我們必須客製化touch event,只有在url被點擊的時候,才使用Textview去處理,其他時候就將event 往下傳遞。


首先要稍微提一下 onTouchEvent的 override
return true  代表這個事件在這邊被處理,所以不會再往下傳遞。
return false 代表事件並未被處理,會繼續向下傳遞。




首先先客製化 LinkMovementMethod 只有在url 被點擊時才處理 (return true)

 public static class LocalLinkMovementMethod extends LinkMovementMethod{
     static LocalLinkMovementMethod sInstance;


     public static LocalLinkMovementMethod getInstance() {
         if (sInstance == null)
             sInstance = new LocalLinkMovementMethod();

         return sInstance;
     }

     @Override
     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]));
                 }

                 if (widget instanceof LinkEnabledTextView){
                     ((LinkEnabledTextView) widget).linkHit = true;
                 }
                 return true;
             } else {
                 Selection.removeSelection(buffer);
                 Touch.onTouchEvent(widget, buffer, event);
                 return false;
             }
         }
         return Touch.onTouchEvent(widget, buffer, event);
     }
 }


接著在客製化的 textView 裡面 override touchevent 和 focus


 @Override
 public boolean hasFocusable() {
  // TODO Auto-generated method stub
  return false;
 }
 
 @Override
 public boolean onTouchEvent(MotionEvent event) {
     linkHit = false;
     boolean res = super.onTouchEvent(event);

     if (dontConsumeNonUrlClicks)
         return linkHit;
     return res;

 }


經過這樣的修改,listview的onitemclick event就不會再被textview吃掉了。

沒有留言:

張貼留言