2014-11-08 16 views
5

Ho bisogno di uno span cliccabile per avere sia un clic normale che un metodo di clic lungo nella mia app e ho scoperto qui (In Android - How can I register only long clicks using a ClickableSpan) che potrei estendere la classe LinkMovementMethod e Classe ClickableSpan per consentire di farlo, ma attualmente i clic lunghi e quelli brevi funzionano entrambi, ma per un clic lungo invece di attivare l'azione del clic lungo quando l'elemento è stato premuto abbastanza a lungo, aspetterà fino a quando non verrà rilasciato l'elemento. Ecco il mio codice per le classi estesi:Long Click su Clickable span che non si attiva finché non si rilascia il clic

LinkMovementClass

import android.text.Layout; 
import android.text.Selection; 
import android.text.Spannable; 
import android.text.method.LinkMovementMethod; 
import android.text.method.MovementMethod; 
import android.view.MotionEvent; 
import android.widget.TextView; 

public class LongClickLinkMovementMethod extends LinkMovementMethod { 

private Long lastClickTime = 0l; 
private int lastX = 0; 
private int lastY = 0; 
@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(); 
     lastX = x; 
     lastY = y; 
     int deltaX = Math.abs(x-lastX); 
     int deltaY = Math.abs(y-lastY); 

     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); 

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

     if (link.length != 0) { 
      if (action == MotionEvent.ACTION_UP) { 
       if (System.currentTimeMillis() - lastClickTime < 1000) 
        link[0].onClick(widget); 
       else if (deltaX < 10 && deltaY < 10) 
        link[0].onLongClick(widget); 
      } else if (action == MotionEvent.ACTION_DOWN) { 
       Selection.setSelection(buffer, 
         buffer.getSpanStart(link[0]), 
         buffer.getSpanEnd(link[0])); 
       lastClickTime = System.currentTimeMillis(); 
      } 
      return true; 
     } 
    } 

    return super.onTouchEvent(widget, buffer, event); 
} 


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

    return sInstance; 
} 
    private static LongClickLinkMovementMethod sInstance; 
} 

LongClickableSpanClass

import android.text.style.ClickableSpan; 
import android.view.View; 

public abstract class LongClickableSpan extends ClickableSpan { 

    abstract public void onLongClick(View view); 
} 

effettiva attuazione

LongClickableSpan eruptionText = new LongClickableSpan() { 

           @Override 
           public void onClick(View tvEruptions) { 
            LinkFunctions.link_eruption_detail(getApplicationContext(),PostErupionID); 
           } 

           @Override 
           public void onLongClick(View tvEruptions) { 
            if(SignedInUserID != 0) { 
             DialogFragment newFragment = new Dialogs.QuickActionsDialogFragment(); 
             // Supply num input as an argument. 
             Bundle args = new Bundle(); 
             args.putLong("eruptionID", PostErupionID); 
             newFragment.setArguments(args); 
             newFragment.show(getFragmentManager(), "QuickActions"); 
            } 
           } 

          }; 
          ss.setSpan(eruptionText, startpos[(int) j], endpos[(int) j], Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 

risposta

5

So che questa domanda è vecchia e, probabilmente, il PO ha già risolto il problema ma ho fatto alcune modifiche sulla LongClickLinkMovementMethod originale al fuoco dopo che il tempo è passato, invece di quando rilasciamo il rubinetto:

import android.os.Handler; 
import android.text.Layout; 
import android.text.Selection; 
import android.text.Spannable; 
import android.text.method.LinkMovementMethod; 
import android.text.method.MovementMethod; 
import android.view.MotionEvent; 
import android.widget.TextView; 


public class LongClickLinkMovementMethod extends LinkMovementMethod { 

    private Handler mLongClickHandler; 
    private static int LONG_CLICK_TIME = 1000; 
    private boolean mIsLongPressed = false; 

    @Override 
    public boolean onTouchEvent(final TextView widget, Spannable buffer, 
           MotionEvent event) { 
     int action = event.getAction(); 

     if(action == MotionEvent.ACTION_CANCEL){ 
      if(mLongClickHandler!=null){ 
       mLongClickHandler.removeCallbacksAndMessages(null); 
      } 
     } 

     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); 

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

      if (link.length != 0) { 
       if (action == MotionEvent.ACTION_UP) { 
        if(mLongClickHandler!=null){ 
         mLongClickHandler.removeCallbacksAndMessages(null); 
        } 
        if(!mIsLongPressed) { 
         link[0].onClick(widget); 
        } 
        mIsLongPressed = false; 
       } else { 
        Selection.setSelection(buffer, 
          buffer.getSpanStart(link[0]), 
          buffer.getSpanEnd(link[0])); 
        mLongClickHandler.postDelayed(new Runnable() { 
         @Override 
         public void run() { 
          link[0].onLongClick(widget); 
          mIsLongPressed = true; 
         } 
        },LONG_CLICK_TIME); 
       } 
       return true; 
      } 
     } 

     return super.onTouchEvent(widget, buffer, event); 
    } 


    public static MovementMethod getInstance() { 
     if (sInstance == null) { 
      sInstance = new LongClickLinkMovementMethod(); 
      sInstance.mLongClickHandler = new Handler(); 
     } 

     return sInstance; 
    } 
    private static LongClickLinkMovementMethod sInstance; 
} 

Così basicaly questo utilizza un gestore per attivare l'evento di clic lungo dopo 1000 ms

3

Il modo semplice è utilizzare View.setTag.

Codice esempio:

tv.setOnLongClickListener(new OnLongClickListener() { 

    @Override 
    public boolean onLongClick(View v) { 
     Toast.makeText(getApplicationContext(), "onLongClick", Toast.LENGTH_SHORT).show(); 
     v.setTag("Test"); 
     return true; 
    } 
}); 

private static class NonLongClickableUrlSpan extends URLSpan { 

    public NonLongClickableUrlSpan(String url) { 
     super(url); 
    } 

    @Override 
    public void onClick(View widget) { 
     if (widget.getTag() != null) { 
      widget.setTag(null); 
      return; 
     } 
     super.onClick(widget); 
    } 
}