¿Qué significa el valor booleano devuelto por un método de manejo de eventos en Android?

110

En Android, la mayoría de los métodos de escucha de eventos devuelven un valor booleano. ¿Qué significa ese valor verdadero / falso? ¿Qué resultará en los eventos posteriores?

class MyTouchListener implements OnTouchListener {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        logView.showEvent(event);
        return true;
    }
}

Con respecto al ejemplo anterior, si se devuelve verdadero en el método onTouch , encontré que cada evento táctil (ABAJO, ARRIBA, MOVIMIENTO, etc.) se ha capturado de acuerdo con mi logView . Por el contrario, si devuelve falso, solo se capturará el evento DOWN. Por lo tanto, parece que devolver falso evitará que el evento se propague. Estoy en lo correcto ?

Además, en OnGestureListener , muchos métodos también tienen que devolver un valor booleano. ¿Tienen el mismo significado?

John Wang
fuente

Respuestas:

140

Si regresa truede un ACTION_DOWNevento, está interesado en el resto de eventos en ese gesto. Un "gesto" en este caso significa todos los eventos hasta el final ACTION_UPo ACTION_CANCEL. Regresar falsede un ACTION_DOWNmedio que no desea el evento y otras vistas tendrán la oportunidad de manejarlo. Si tiene vistas superpuestas, esta puede ser una vista hermana. Si no, se le ocurrirá a los padres.

adamp
fuente
3
adamp, ¿hay alguna manera de seguir recibiendo eventos Y dejar pasar los eventos?
ticofab
@ticofab no, solo un padre de la vista que recibe eventos actualmente puede interceptar eventos futuros en el gesto. (Por supuesto, siempre puede crear sus propios sistemas de redireccionamiento en una vista principal, pero no lo recomendaría a menos que realmente sepa lo que está haciendo. :))
adamp
@adamp No puedo pensar en la razón por la que onTouch se llama 2 veces cuando devuelve verdadero y 1 vez solo cuando devuelvo falso.
Bhargav Jhaveri
1
@adamp: estoy devolviendo falso de ACTION_DOWN pero mi ACTION_UP se activa y ejecuta.
Mahantesh M Ambi
¿Estoy recibiendo esta respuesta incorrecta o todos los demás están ... Esta respuesta decía que devolver verdadero significa que el evento difícil no se consume. Pero la verdad es completamente al revés.
Kai Wang
12

El valor booleano determina si el evento se consume o no.

Sí, tienes razón. Si devuelve falso, el siguiente oyente maneja el evento. Si devuelve verdadero, su oyente consume el evento y no lo envía al siguiente método.

Falmarri
fuente
2
Eso es falso. truesignifica que consumió el evento y desea el resto de los eventos en el gesto; otros oyentes / vistas no recibirán los eventos. falsesignifica dejar que otra persona se encargue del evento. Sin embargo, es un poco más específico que eso; mira mi respuesta.
adamp
¿Cómo no es eso exactamente lo que dije?
Falmarri
1
Lo que dijiste está al revés. :)
adamp
4

Toda la respuesta anterior es correcta, pero el resultado es diferente si la vista es clickableo noclickable

Ejemplo , tengo un LinearLayoutcontiene 1 Buttony 1 TextViewcomo este

<LinearLayout
    android:id="@+id/linearlayout_root"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0aa"
    android:orientation="vertical">

    <Button
        android:id="@+id/button_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="40dp"
        android:text="Button Click"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/textview_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="40dp"
        android:text="TextView Click"
        android:textSize="20sp"
        android:background="#e4e4e4"
        />

</LinearLayout>

En Actividad, tengo un código como

class MainActivity : AppCompatActivity() {
    val TAG = "TAG"

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<LinearLayout>(R.id.linearlayout_root).setOnTouchListener { v, event ->
            Log.i(TAG, "LinearLayout onTouch event " + getDisplayAction(event.action))
            false
        }

        findViewById<Button>(R.id.button_click).setOnTouchListener { v, event ->
            Log.i(TAG, "Button onTouch event " + getDisplayAction(event.action))
            false
        }

        findViewById<TextView>(R.id.textview_click).setOnTouchListener { v, event ->
            Log.i(TAG, "TextView onTouch event " + getDisplayAction(event.action))
            false
        }
    }

    private fun getDisplayAction(action: Int): String {
        return when (action) {
            MotionEvent.ACTION_DOWN -> "DOWN"
            MotionEvent.ACTION_MOVE -> "MOVE"
            MotionEvent.ACTION_UP -> "UP"
            MotionEvent.ACTION_CANCEL -> "CANCEL"
            MotionEvent.ACTION_OUTSIDE -> "OUTSIDE"
            else -> "UNKNOWN"
        }
    }
}

Caso 1 Linear onTouch return **FALSE**, Button onTouch return **FALSE**,TextView onTouch return **FALSE**

Haga clic en el botón

I/TAG: Button onTouch eventDOWN
I/TAG: Button onTouch eventMOVE
I/TAG: Button onTouch eventUP

Haga clic en TextView

TAG: TextView onTouch eventDOWN
TAG: LinearLayout onTouch eventDOWN

Haga clic en LinearLayout

TAG: LinearLayout onTouch eventDOWN

Caso 2 Linear onTouch return **FALSE**, Button onTouch return **TRUE**,TextView onTouch return **TRUE**

Haga clic en el botón

Similar to case 1

Haga clic en TextView

TAG: TextView onTouch event DOWN
TAG: TextView onTouch event MOVE
TAG: TextView onTouch event UP

Haga clic en LinearLayout

Similar to case 1

Caso 3 Linear onTouch return **TRUE**, Button onTouch return **FALSE**,TextView onTouch return **FALSE**

Haga clic en el botón

Similar to case 1

Haga clic en TextView

TAG: TextView onTouch event DOWN
TAG: LinearLayout onTouch event DOWN
TAG: LinearLayout onTouch event MOVE
TAG: LinearLayout onTouch event UP

Haga clic en LinearLayout

TAG: LinearLayout onTouch event DOWN
TAG: LinearLayout onTouch event MOVE
TAG: LinearLayout onTouch event UP

Nota

  • El valor predeterminado TextViewes not clickable, se podrá hacer clic en él si lo configuramos android:clickable="true"en xml O cuando configuramostextView.setOnClickListener(...)
  • Cuando depura, event MOVEpuede llamar más que mi registro (se basa en cómo toca)

Resumen

  • onTouchvolver trueo ver es clickable , Ver recibirá todo onTouchEvent
  • onTouchvolver falsey la vista no es clickable, la vista no recibirá SIGUIENTE onTouchEvent (su padre puede recibirlo)

Espero que ayude a
DEMO

Phan Van Linh
fuente
1
¡Esta debería ser la respuesta! Gracias por una explicación tan detallada
Mysterious_android
1

Perdí casi un día en la resolución de problemas, pero descubrí que mi función onTouch se llama 2 veces cuando se usa verdadero y 1 veces cuando se usa falso.

Kamor
fuente
¿Podrías averiguar la razón?
Bhargav Jhaveri
verifique event.getAction()porque si regresa falseen el evento ACTION_DOWN, el oyente ignora el evento
ACTION_UP
0

Desde el documento de Android :

Nota: Android llamará a los controladores de eventos primero y luego a los controladores predeterminados apropiados de la definición de clase en segundo lugar. Como tal, devolver true de estos detectores de eventos detendrá la propagación del evento a otros detectores de eventos y también bloqueará la devolución de llamada al controlador de eventos predeterminado en la Vista. Así que asegúrese de que desea finalizar el evento cuando devuelva verdadero.

Huy Nguyen
fuente