2016-11-20 81 views
5

我有一個TextView其中每個單詞是ClickableSpan。單擊時,單詞變成加粗並且單詞的字典定義顯示在另一個TextView中。該應用程序正常工作,直到我使TextView中的文本可選。當文本可選時,定義會在點擊中顯示,但雙擊時該字只有加粗。雙擊或長按選擇文本(但長按不會使文字變粗)。處理ClickableSpan與可選文本需要雙擊

我的猜測是這個問題與動作處理過程中的繪製狀態更新有關,但我無法找到修復。我試圖設置TextViewfocusable="false"但沒有任何改變。相關代碼如下。

curSpan = new WordSpan(index) { 
    @Override 
    public void onClick(View view) { 
     handleWordClick(index,this); // handles code to display definition 
     setMarking(true); 
     view.invalidate(); 
     tvText.invalidate(); 
    } 
}; 

spannableStringBuilder.setSpan(curSpan, totalLength, totalLength + strWord, Spanned.SPAN_COMPOSING); 

而且WordSpan定義:

class WordSpan extends ClickableSpan 
    { 
     int id; 
     private boolean marking = false; 

     public WordSpan(int id) { 
      this.id = id; 
     } 

     @Override 
     public void updateDrawState(TextPaint ds) { 
      ds.setColor(Color.BLACK); 
      ds.setUnderlineText(false); 
      if (marking) { 
       ds.setTypeface(Typeface.create(myFont,Typeface.BOLD)); 
      } 
     } 

     @Override 
     public void onClick(View v) {} 

     public void setMarking(boolean m) { 
      marking = m; 
     } 
    } 

設置運動方法TextView的:

private MovementMethod createMovementMethod (Context context) { 
     final GestureDetector detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
       @Override 
       public boolean onSingleTapUp (MotionEvent e) { 
        return true; 
       } 

       @Override 
       public boolean onSingleTapConfirmed (MotionEvent e) { 
        return true; 
       } 
      }); 

     return new ScrollingMovementMethod() { 

      @Override 
      public boolean canSelectArbitrarily() { 
       return true; 
      } 

      @Override 
      public void initialize(TextView widget, Spannable text) { 
       Selection.setSelection(text, text.length()); 
      } 

      @Override 
      public void onTakeFocus(TextView view, Spannable text, int dir) { 
       if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) { 
        if (view.getLayout() == null) { 
         // This shouldn't be null, but do something sensible if it is. 
         Selection.setSelection(text, text.length()); 
        } 
       } else { 
        Selection.setSelection(text, text.length()); 
       } 
      } 

      @Override 
      public boolean onTouchEvent (TextView widget, Spannable buffer, MotionEvent event) { 
       // check if event is a single tab 
       boolean isClickEvent = detector.onTouchEvent(event); 

       // detect span that was clicked 
       if (isClickEvent) { 
        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); 

        WordSpan[] link = buffer.getSpans(off, off, WordSpan.class); 

        if (link.length != 0) { 
         // execute click only for first clickable span 
         // can be a for each loop to execute every one 
         if (event.getAction() == MotionEvent.ACTION_UP) { 
          link[0].onClick(widget); 
         } else if (event.getAction() == MotionEvent.ACTION_DOWN) { 
          Selection.setSelection(buffer, 
                buffer.getSpanStart(link[0]), 
                buffer.getSpanEnd(link[0])); 
         } 
         return true; 
        } 
       } 

       // let scroll movement handle the touch 
       return super.onTouchEvent(widget, buffer, event); 
      } 
     }; 
    } 

編輯: 我剛剛發現了一個新的怪癖,可以解決幫助。如果我雙擊但單擊之間改變單詞(點擊一個單詞&,然後快速選擇另一個單詞),在第一次敲擊時顯示該單詞的定義,在第二次敲擊時,第一個單詞顯示爲粗體,但第二個單詞被選中(突出顯示)並且第一個字的定義仍然顯示。

因此,舉例來說,如果我槍王「第一」,然後「第二」,當我點擊 「第一」的定義爲「第一」將顯示,當我觸摸 「第二個」一字「第一個「是粗體字,」second「字是突出顯示的 ,但定義不變(仍然顯示 」第一個「的定義)。

+0

嘿!我是否正確理解問題。如何處理帶有不同可點擊文本的Spannable String的TextView雙擊? – GensaGames

+0

它應該是單擊而不是雙擊。當用戶點擊單詞時,應該加粗單詞並顯示定義。雙擊不應該做任何事情。 –

回答

0

用以下替換createMovementMethod。如果你錯誤面對錯誤PLZ修復它並編輯這個答案。

private MovementMethod createMovementMethod (final Context context) { 

     return new ScrollingMovementMethod() { 
      public MotionEvent event; 
      public Spannable buffer; 
      public TextView widget; 
      final GestureDetector detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
       @Override 
       public boolean onSingleTapUp (MotionEvent e) { 

        return true; 
       } 

       @Override 
       public boolean onSingleTapConfirmed (MotionEvent e) { 
        triggerClick(); 
        return true; 
       } 

       @Override 
       public boolean onDoubleTap(MotionEvent e) { 
        triggerClick(); 
        return true; 
       } 

       private boolean triggerClick() { 
        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); 

        WordSpan[] link = buffer.getSpans(off, off, WordSpan.class); 

        if (link.length != 0) { 
         // execute click only for first clickable span 
         // can be a for each loop to execute every one 
         if (event.getAction() == MotionEvent.ACTION_UP) { 
          link[0].onClick(widget); 
         } else if (event.getAction() == MotionEvent.ACTION_DOWN) { 
          Selection.setSelection(buffer, 
            buffer.getSpanStart(link[0]), 
            buffer.getSpanEnd(link[0])); 
         } 
         return true; 
        } 

        return true; 
       } 
      }); 
      @Override 
      public boolean canSelectArbitrarily() { 
       return true; 
      } 

      @Override 
      public void initialize(TextView widget, Spannable text) { 
       Selection.setSelection(text, text.length()); 
      } 

      @Override 
      public void onTakeFocus(TextView view, Spannable text, int dir) { 
       if ((dir & (View.FOCUS_FORWARD | View.FOCUS_DOWN)) != 0) { 
        if (view.getLayout() == null) { 
         // This shouldn't be null, but do something sensible if it is. 
         Selection.setSelection(text, text.length()); 
        } 
       } else { 
        Selection.setSelection(text, text.length()); 
       } 
      } 

      @Override 
      public boolean onTouchEvent (TextView widget, Spannable buffer, MotionEvent event) { 
       // check if event is a single tab 
       boolean isClickEvent = detector.onTouchEvent(event); 

       //record this for GestureDetector 
       this.widget = widget; 
       this.buffer = buffer; 
       this.event = event; 

       // detect span that was clicked 
       if (isClickEvent) { 
        //ignore click here 
        return true; 
       } 

       // let scroll movement handle the touch 
       return super.onTouchEvent(widget, buffer, event); 
      } 
     }; 
    } 
+0

感謝您的回覆,但這不能解決問題,並增加了觸摸時選擇了錯誤詞彙的其他問題。 –

+0

此外,onDoubleTap()不會由雙擊觸發。它只在雙擊時才起作用,但是這種方法沒有被觸發,所以我無法捕捉它,並且像這個答案一樣嘗試去重定向。 –

+0

是的,我知道,需要類似的東西。它沒有測試你需要修復它並編輯答案本身。謝謝 – Qamar