Maison  >  Article  >  Java  >  Comprendre le mécanisme de distribution d'événements Android Touch en 30 minutes

Comprendre le mécanisme de distribution d'événements Android Touch en 30 minutes

高洛峰
高洛峰original
2017-01-16 16:46:051209parcourir

Il n'y a que deux protagonistes dans la distribution d'événements Touch : ViewGroup et View. L'événement Touch d'Activity appelle en fait l'événement Touch de son ViewGroup interne et peut être traité directement en tant que ViewGroup.

View est dans un ViewGroup, et un ViewGroup peut également être dans un autre ViewGroup. À ce stade, le ViewGroup interne est analysé comme une View.

Il existe trois événements associés pour ViewGroup : onInterceptTouchEvent, dispatchTouchEvent et onTouchEvent. Il n'existe que deux événements associés pour View : dispatchTouchEvent et onTouchEvent.

Analysez d'abord le flux de traitement de ViewGroup : Tout d'abord, il doit y avoir un concept de modèle structurel : ViewGroup et View forment une structure arborescente. Le niveau supérieur est le ViewGroup d'activité. Il y a plusieurs nœuds ViewGroup en dessous de chaque nœud. Il y a plusieurs nœuds ViewGroup ou nœuds View en dessous, et ainsi de suite. Comme le montre l'image :

30分钟搞清楚Android Touch事件分发机制

Lorsqu'un événement Touch (événement tactile par exemple) atteint le nœud racine, c'est-à-dire le ViewGroup d'Active, il sera délivré dans l'ordre. Le processus de livraison consiste à appeler Implémenté par la méthode dispatchTouchEvent de la sous-Vue (ViewGroup). Pour faire simple, le ViewGroup parcourt les sous-Vues qu'il contient et appelle la méthode dispatchTouchEvent de chaque View. Lorsque la sous-View est un ViewGroup, il continuera à appeler la méthode dispatchTouchEvent de sa View interne en appelant la méthode dispatchTouchEvent de. VisualGroup. La séquence de livraison des messages dans l'exemple ci-dessus est la suivante : ①-②-⑤-⑥-⑦-③-④. La méthode dispatchTouchEvent est uniquement responsable de la distribution des événements. Elle a une valeur de retour booléenne. Lorsque la valeur de retour est vraie, la livraison séquentielle sera interrompue. Dans l'exemple ci-dessus, si le dispatchTouchEvent de ⑤ renvoie vrai, alors ⑥-⑦-③-④ ne recevra pas cet événement Touch. Prenons une version simple du code pour approfondir notre compréhension :

/**
   * ViewGroup
   * @param ev
   * @return
   */
  public boolean dispatchTouchEvent(MotionEvent ev){
    ....//其他处理,在此不管
    View[] views=getChildView();
    for(int i=0;i<views.length;i++){
      //判断下Touch到屏幕上的点在该子View上面 
      if(...){
      if(views[i].dispatchTouchEvent(ev))
       return true;
       }
    }
    ...//其他处理,在此不管
  }
  /**
   * View
   * @param ev
   * @return
   */
  public boolean dispatchTouchEvent(MotionEvent ev){
    ....//其他处理,在此不管
    return false;
  }

Comme vous pouvez le voir ici, dispatchTouchEvent de ViewGroup effectue réellement un travail de « distribution », tandis que la méthode dispatchTouchEvent de View n'effectue pas de travail de distribution, ou en En d'autres termes, l'objet qu'il distribue est lui-même, et il décide s'il doit se transmettre l'événement touch pour le traitement, et la méthode de traitement est l'événement onTouchEvent. En fait, le code réellement exécuté par la méthode dispatchTouchEvent de la sous-vue est. comme ça

/**
   * View
   * @param ev
   * @return
   */
  public boolean dispatchTouchEvent(MotionEvent ev){
    ....//其他处理,在此不管
    return onTouchEvent(event);
  }

Dans des circonstances normales, nous ne devrions pas remplacer la méthode dispatchTouchEvent dans une vue normale car elle n'effectue pas de logique de distribution. Lorsque l'événement Touch atteint la vue, nous devons savoir s'il faut le gérer dans l'événement onTouchEvent.

Alors, quand l'événement onTouchEvent de ViewGroup est-il traité ? Lorsque toutes les sous-vues du ViewGroup renvoient false, l'événement onTouchEvent sera exécuté. Étant donné que ViewGroup hérite de View, il exécute en fait l'événement onTouchEvent en appelant la méthode dispatchTouchEvent de View.

D'après la situation actuelle, il semble que tant que nous renvoyons false à tous les onTouchEvents, nous pouvons garantir que tous les sous-contrôles répondent à cet événement Touch. Mais il faut noter que l'événement Touch ici est limité à l'événement Action_Down, c'est-à-dire l'événement touch press, tandis qu'Aciton_UP et Action_MOVE ne seront pas exécutés. En fait, un événement Touch complet devrait comprendre un Down, un Up et plusieurs Moves. Le mode Down est distribué via dispatchTouchEvent. Le but de la distribution est de trouver la vue qui a réellement besoin de gérer la demande Touch complète. Lorsque l'événement onTouchEvent d'une vue ou d'un ViewGroup renvoie vrai, cela signifie que c'est la vue qui souhaite réellement gérer cette demande, et que les Aciton_UP et Action_MOVE suivants seront gérés par elle. Lorsque le onTouchEvent de toutes les vues enfants renvoie false, cette requête Touch est gérée par le ViewGroup racine, c'est-à-dire l'activité elle-même.

Regardez la méthode dispatchTouchEvent améliorée de ViewGroup

View mTarget=null;//保存捕获Touch事件处理的View
  public boolean dispatchTouchEvent(MotionEvent ev) {
 
    //....其他处理,在此不管
     
    if(ev.getAction()==KeyEvent.ACTION_DOWN){
      //每次Down事件,都置为Null
 
      if(!onInterceptTouchEvent()){
      mTarget=null;
      View[] views=getChildView();
      for(int i=0;i<views.length;i++){
        if(views[i].dispatchTouchEvent(ev))
          mTarget=views[i];
          return true;
      }
     }
    }
    //当子View没有捕获down事件时,ViewGroup自身处理。这里处理的Touch事件包含Down、Up和Move
    if(mTarget==null){
      return super.dispatchTouchEvent(ev);
    }
    //...其他处理,在此不管
    if(onInterceptTouchEvent()){
     //...其他处理,在此不管  
     }
//这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。
    return mTarget.dispatchTouchEvent(ev);
 
  }

ViewGroup a également un onInterceptTouchEvent Vous pouvez dire d'après le nom qu'il s'agit d'un événement d'interception. Cet événement d'interception doit être expliqué dans deux situations :

1. Si nous retournons true dans le onInterceptTouchEvent d'un ViewGroup et que l'Action est Down pour l'événement Touch, cela signifie que toutes les opérations émises par le ViewGroup le seront. be Interceptez-le. Dans ce cas, mTarget sera toujours nul, car mTarget se voit attribuer une valeur dans l'événement Down. Puisque mTarge est nul, l'événement onTouchEvent de ViewGroup est exécuté. Dans ce cas, le ViewGroup peut être traité directement comme une View.

2. Si nous sommes dans onInterceptTouchEvent d'un certain ViewGroup, tous les événements Touch dont l'action est Down renvoient false, et d'autres renvoient True. Dans ce cas, l'événement Down peut être distribué normalement si l'enfant voit tout. renvoie false, alors mTarget est toujours vide, aucun impact. Si une sous-vue renvoie vrai et que mTarget se voit attribuer une valeur, lorsque Action_Move et Aciton_UP sont distribués au ViewGroup, un MotionEvent de Action_Delete sera distribué à mTarget et la valeur de mTarget sera effacée en même temps, de sorte que le next Action_Move (si l'opération précédente n'est pas UP) sera gérée par onTouchEvent de ViewGroup.

La situation 1 est utilisée plus souvent, tandis que la situation 2 n'a pas encore été utilisée.

Pour résumer du début à la fin :

1. Il n'y a que deux protagonistes dans la distribution d'événements Touch : ViewGroup et View. ViewGroup contient trois événements associés : onInterceptTouchEvent, dispatchTouchEvent et onTouchEvent. La vue contient deux événements liés : dispatchTouchEvent et onTouchEvent. Parmi eux, ViewGroup hérite de View.

2. ViewGroup et View forment une structure arborescente, et le nœud racine est un ViwGroup contenu dans l'activité.

3. Les événements tactiles sont composés d'Action_Down, Action_Move et Aciton_UP. Dans un événement tactile complet, il n'y a qu'un seul Down et Up, et il y a plusieurs Moves, qui peuvent être nuls.

4. Lorsqu'Activity reçoit l'événement Touch, il traverse la sous-vue pour distribuer l'événement Down. Le parcours ViewGroup peut être considéré comme récursif. Le but de la distribution est de trouver la vue qui gère réellement cet événement tactile complet. Cette vue renverra true dans le résultat onTouchuEvent.

5. Lorsqu'une sous-vue renvoie vrai, la distribution de l'événement Down sera arrêtée et la sous-vue sera enregistrée dans le ViewGroup. Les événements Move et Up suivants seront gérés directement par la sous-vue. Étant donné que la sous-vue est enregistrée dans ViewGroup, dans la structure de nœuds ViewGroup multicouche, le ViewGroup de niveau supérieur enregistre l'objet ViewGroup là où se trouve la vue qui gère réellement l'événement : par exemple, dans la structure ViewGroup0-ViewGroup1. -TextView, TextView renvoie true, qui sera enregistré dans ViewGroup1, et ViewGroup1 renverra également true et sera enregistré dans ViewGroup0. Lorsque les événements Move et UP arrivent, ils seront d'abord transmis de ViewGroup0 à ViewGroup1, puis de ViewGroup1 à TextView.

6. Lorsque toutes les sous-vues du ViewGroup ne capturent pas l'événement Down, l'événement onTouch du ViewGroup lui-même sera déclenché. La façon de déclencher consiste à appeler la fonction super.dispatchTouchEvent, qui est la méthode dispatchTouchEvent de la classe parent View. Lorsque toutes les sous-vues ne sont pas traitées, la méthode onTouchEvent d'activité est déclenchée.

7.onInterceptTouchEvent a deux fonctions : 1. Intercepter la distribution des événements Down. 2. Arrêtez la transmission des événements Up et Move à la vue cible, afin que le ViewGroup où se trouve la vue cible capture les événements Up et Move.
Supplément :

"Les événements tactiles sont composés d'Action_Down, Action_Move et Aciton_UP. Dans un événement tactile complet, il n'y a qu'un seul Down et Up, et il y a plusieurs Moves, qui peuvent être 0." , ici De plus, en fait, il peut y avoir 0 événement UP.
Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à tout le monde de comprendre le mécanisme de distribution des événements Touch.

Pour plus d'articles sur la compréhension du mécanisme de distribution d'événements Android Touch en 30 minutes, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn