Detectar clics largos en una vista personalizada?

Tengo una vista personalizada que amplía FrameLayout y implementa ScaleGestureDetector.OnScaleGestureListener . Esta vista, como el nombre de la clase sugiere, es zoomable + pannable. Heres la clase de vistas personalizadas: https://gist.github.com/Orbyt/23c82ce9002df6c318d4

He estado tratando de encontrar una forma de detectar clics largos en esta vista. Sé que, por lo general, podría hacer algo como esto en la Actividad:

 GestureDetector mGestureDetector = new GestureDetector(this, this); mZoomableLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mGestureDetector.onTouchEvent(event); } }); mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { @Override public void onLongPress(MotionEvent e) { // do tasks here } }); 

Usando esto, el View ya no es zoomable, presumiblemente porque intercepta todos los eventos onTouch en lugar de la implementación dentro de la clase Views.

Así que mi pregunta es, ¿cuál es la manera más limpia de detectar clics largos en esta vista?

Tuve un pinch zoom círculo en el que he detectado el clic normal y click.Code largo snippet se da a continuación. En esto he detectado un clic largo y normal haga clic en el intervalo de tiempo entre MotionEvent.ACTION_DOWN y MotionEvent.ACTION_UP.

Que esto te ayude.

  private static final int MAX_CLICK_DURATION = 200; private float mScaleFactor = 1.0000000f; private long mStartClickTime; @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); boolean right = x > (screenWidthPX / 2 + ((mLayoutHeight / 4) + 20) * mScaleFactor); boolean left = x < (screenWidthPX / 2 - ((mLayoutHeight / 4) + 20) * mScaleFactor); boolean top = y > (mLayoutHeight / 2 + ((mLayoutHeight / 4) + 20) * mScaleFactor); boolean bottom = y < (mLayoutHeight / 2 - ((mLayoutHeight / 4) + 20) * mScaleFactor); if (event.getPointerCount() > 1) { if (left || right || top || bottom) { // You may not need this condtion, I needed this because I had custom view of pinch zoom circle and, this condition detects the touch at outer area of circle. } else { mScaleGestureDetector.onTouchEvent(event); } } else { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mStartClickTime = Calendar.getInstance().getTimeInMillis(); break; } case MotionEvent.ACTION_UP: { long clickDuration = Calendar.getInstance().getTimeInMillis() - mStartClickTime; if (clickDuration < MAX_CLICK_DURATION) { if (left || right || top || bottom) { } else { Toast.makeText(mContext, "Normal CLick Detected", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(mContext, "Long CLick Detected", Toast.LENGTH_SHORT).show(); } } } } return true; } 

Ok, lo siento, no entendí su problema en absoluto. Ahora en su MainActivity:

 public yourMainConstructor() { [...] GestureDetector sgd; sgd = new GestureDetector(context,new ScaleListener()); [...] } class ScaleListener extends GestureDetector.SimpleOnGestureListener { @Override public void onLongPress(MotionEvent e) { super.onLongPress(e); } } 

Entonces anula en su clase principal onTouchEvent ()

 @Override public boolean onTouchEvent(MotionEvent event) { sgd.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: [...] } } 

En primer lugar, necesitará utilizar el toque para distinguir entre el movimiento real y el movimiento involuntario del dedo del usuario (ver ACTION_MOVE). Segundo, si está extendiendo FrameLayout , es más limpio reemplazar onTouchEvent lugar de this.setOnTouchListener en init() .

Agregue variables a su vista personalizada:

 private final Handler mHandler = new Handler(); private ScaleGestureDetector mScaleDetector; private int mTouchSlop; private Runnable mLongPressed = new Runnable() { public void run() { Log.i(TAG, "Long press!"); //Do your long press stuff here. } }; 

Dentro de init() :

 mScaleDetector = new ScaleGestureDetector(context, this); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 

En la instrucción switch:

 switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //Whatever you were doing previously here mHandler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout()); break; case MotionEvent.ACTION_MOVE: if (mode == Mode.DRAG) { dx = motionEvent.getX() - startX; dy = motionEvent.getY() - startY; if(Math.abs(dx) > mTouchSlop || Math.abs(dy) > mTouchSlop) { //Actual movement mHandler.removeCallbacks(mLongPressed); } else { //Below touch slop, not a movement dx = 0; dy = 0; } } break; case MotionEvent.ACTION_POINTER_DOWN: mHandler.removeCallbacks(mLongPressed); //Whatever you were doing previously here break; case MotionEvent.ACTION_POINTER_UP: mHandler.removeCallbacks(mLongPressed); //Whatever you were doing previously here break; case MotionEvent.ACTION_UP: mHandler.removeCallbacks(mLongPressed); //Whatever you were doing previously here break; } //Whatever you were doing previously here 

Ahora las tres funcionalidades están funcionando.

Si el punto del tecleo largo es necesario hacer una clase abstracta que implemente Runnable con los flotadores xyy los llene en ACTION_DOWN , después utiliza coordenadas en el run()

  • Cambiar el comportamiento de un GridView para que se desplace horizontalmente en lugar de verticalmente
  • Las vistas agregadas a TableLayout no se muestran mediante programación
  • ¿Cómo puedo dibujar una vista animada en android?
  • Personalización de la barra de desplazamiento vertical de Android ScrollView
  • Habilitar longClick en WebView
  • No se puede eliminar una vista adjunta por windowManager.addView ()
  • Cookies HTTP WebView HTTP no funcionan en la API 21
  • Diferencia entre vista y subvista - Android
  • Cómo implementar Swipe en Android juego sin vista
  • Ver buscapersonas y listview
  • ViewPager dentro de CoordinatorLayout cubre otras vistas en API> = 21
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.