Quelle est la signification de la valeur booléenne renvoyée par une méthode de gestion des événements dans Android

110

Sous Android, la plupart des méthodes d'écoute d'événements renvoient une valeur booléenne. Que signifie cette valeur vraie / fausse? quel sera le résultat des événements de sous-séquence?

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

En ce qui concerne l'exemple ci-dessus, si le retour est vrai dans la méthode onTouch , j'ai trouvé que chaque événement tactile (DOWN, UP, MOVE, etc.) a été capturé selon mon logView . Au contraire, si return false, seul l'événement DOWN a été capturé. Il semble donc que return false empêchera l'événement de se propager. Ai-je raison ?

De plus, dans un OnGestureListener , de nombreuses méthodes doivent également renvoyer une valeur booléenne. Ont-ils la même signification?

John Wang
la source

Réponses:

140

Si vous revenez trued'un ACTION_DOWNévénement, vous êtes intéressé par le reste des événements de ce geste. Un «geste» dans ce cas signifie tous les événements jusqu'à la finale ACTION_UPou ACTION_CANCEL. Revenir falsed'un ACTION_DOWNendroit signifie que vous ne voulez pas l'événement et que d'autres vues auront l'occasion de le gérer. Si vous avez des vues qui se chevauchent, cela peut être une vue sœur. Sinon, cela reviendra au parent.

adamp
la source
3
adamp, y a-t-il un moyen de continuer à recevoir des événements ET de laisser passer les événements?
ticofab
@ticofab non, seul un parent de la vue recevant actuellement les événements peut intercepter les événements futurs dans le geste. (Bien sûr, vous pouvez toujours créer vos propres systèmes de redirection dans une vue parent, mais je ne le recommanderais pas à moins que vous ne sachiez vraiment ce que vous faites. :))
adamp
@adamp Je ne peux pas penser à la raison pour laquelle onTouch est appelé 2 fois en renvoyant true et 1 fois uniquement lorsque je retourne false.
Bhargav Jhaveri
1
@adamp: Je retourne false de ACTION_DOWN mais mon ACTION_UP est déclenché et exécuté.
Mahantesh M Ambi
Est-ce que je me trompe dans cette réponse ou tout le monde est ... Cette réponse dit que le retour vrai signifie qu'un événement difficile n'est pas consommé. Mais la vérité est complètement inverse.
Kai Wang
12

La valeur booléenne détermine si l'événement est consommé ou non.

Oui, vous avez raison. Si vous retournez false, le prochain écouteur gère l'événement. S'il renvoie true, l'événement est consommé par votre auditeur et n'est pas envoyé à la méthode suivante.

Falmarri
la source
2
C'est faux. truesignifie que vous avez consommé l'événement et que vous voulez le reste des événements dans le geste - les autres écouteurs / vues ne recevront pas les événements. falsesignifie laisser quelqu'un d'autre gérer l'événement. C'est en fait un peu plus précis que cela cependant; voir ma réponse.
adamp le
Comment n'est-ce pas exactement ce que j'ai dit?
Falmarri
1
Ce que vous avez dit est inversé. :)
adamp le
4

Toutes les réponses ci-dessus sont correctes mais le résultat est différent si la vue est clickableou nonclickable

Exemple , j'ai un LinearLayoutcontient 1 Buttonet 1 TextViewcomme ça

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

Dans Activity, j'ai du code comme

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"
        }
    }
}

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

Cliquez sur le bouton

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

Cliquez sur TextView

TAG: TextView onTouch eventDOWN
TAG: LinearLayout onTouch eventDOWN

Cliquez sur LinearLayout

TAG: LinearLayout onTouch eventDOWN

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

Cliquez sur le bouton

Similar to case 1

Cliquez sur TextView

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

Cliquez sur LinearLayout

Similar to case 1

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

Cliquez sur le bouton

Similar to case 1

Cliquez sur TextView

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

Cliquez sur LinearLayout

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

Remarque

  • La valeur par défaut TextViewest not clickable, il deviendra cliquable si nous définissons android:clickable="true"en xml OU lorsque nous définissonstextView.setOnClickListener(...)
  • Lorsque vous déboguez, event MOVE pouvez appeler plus que mon journal (il repose sur la façon dont vous appuyez)

Résumé

  • onTouchretour trueou vue est clickable , View recevra tout onTouchEvent
  • onTouchretour falseet vue n'est pas clickable, vue sera ne recevra pas NEXT onTouchEvent (son parent peut le recevoir)

J'espère que cela aidera
DEMO

Phan Van Linh
la source
1
Cela devrait être la réponse! Merci pour une explication aussi détaillée
Mysterious_android
1

J'ai perdu près d'un jour en dépannage, mais j'ai encore découvert que ma fonction onTouch est appelée 2 fois en utilisant true et 1 fois en utilisant false.

kamor
la source
Pouvez-vous trouver la raison?
Bhargav Jhaveri
vérifiez le event.getAction()car si vous revenez falsesur l'événement ACTION_DOWN, l'événement ACTION_UP est ignoré par l'auditeur
doodeec
0

Depuis le document Android :

Remarque: Android appellera d'abord les gestionnaires d'événements, puis les gestionnaires par défaut appropriés à partir de la définition de classe. En tant que tel, retourner true à partir de ces écouteurs d'événements arrêtera la propagation de l'événement vers d'autres écouteurs d'événements et bloquera également le rappel du gestionnaire d'événements par défaut dans la vue. Assurez-vous donc de vouloir mettre fin à l'événement lorsque vous renvoyez true.

Huy Nguyen
la source