2016-11-20 13 views
5

У меня есть TextView, в котором каждое слово является ClickableSpan. При щелчке слово становится bold, а словарное слово слова указано в другом 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); 
      } 
     }; 
    } 

Edit: Я только что открыл новую причуду, которая может помочь в решении. Если я дважды щелкнул, но изменил слова между щелчками (коснитесь одним словом &, тогда будет другое слово быстро), при первом нажатии будет показано определение для этого слова, а на втором касании слово FIRST выделено жирным шрифтом, но выбрано SECOND word (выделено), и определение для ПЕРВОГО слова все еще показано.

Так, например, если я дважды нажмите «первый», а затем «второй», когда я нажимаю «первый» определение для «первого» будет показано ниже, и, когда я прикасаюсь «второй» слово " сначала "выделено полужирным шрифтом, а слово" второе "выделено , но определение не изменяется (по-прежнему отображается определение для " first ").

+0

Привет! Правильно ли я понимаю вопрос. Как обращаться с двойным кликом по TextView с помощью Spannable String с другим текстом, который можно щелкнуть? – 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