1e41f4b71Sopenharmony_ci# Multi-level Gesture Events
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ciMulti-level gesture events occur when both parent and child components receive a gesture or event bound to them. Handling such events can be tricky: The gesture and event detection is affected by a plurality of factors, with much transmission and competition involved, and an unexpected response easily occurs.
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciThis topic describes the default response sequence of multi-level gesture events and how to set related attributes to affect the response sequence of multi-level gesture events.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ci## Default Multi-level Gesture Events
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci### Touch Event
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ciThe touch event (**onTouch**) is the foundation of all gestures. It comes in four types: Down, Move, Up, and Cancel. A gesture is a sequence of touch events. For example, tap gestures include Down and Up events, and swipe gestures include Down, Move, and Up events. Touch events have the most particularity:
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci1. If a component that has the **onTouch** listener added is touched, it receives the callback of the **onTouch** event. Detection of a touch is subject to the touch target and touch control.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci2. The callback of the **onTouch** event is in a closed-loop manner. If a component receives a Down event whose finger ID is 0, it will also receive a Move event and an Up event whose finger ID is 0.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci3. The callback of the **onTouch** event follows consistency. If a component receives the Down event whose finger ID is 0 but does not receive the Down event whose finger ID is 1, it will receive other touch events whose finger ID is 0, but not touch events whose finger ID is 1.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ciFor common container components (such as **Column**), **onTouch** events can be received by parent and child components at the same time, and how they are received by sibling components is subject to the layout.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci```ts
22e41f4b71Sopenharmony_ciComponentA() {
23e41f4b71Sopenharmony_ci    ComponentB().onTouch(() => {})
24e41f4b71Sopenharmony_ci    ComponentC().onTouch(() => {})
25e41f4b71Sopenharmony_ci}.onTouch(() => {})
26e41f4b71Sopenharmony_ci```
27e41f4b71Sopenharmony_ciIf components B and C are children of component A, then touching component B or component C also touches component A. The **onTouch** callback can be invoked by multiple components at the same time.
28e41f4b71Sopenharmony_ciTherefore, when component B is touched, the **onTouch** callback is invoked by both component A and component B, but not by component C; when component C is touched, the **onTouch** callback is invoked by both component A and component C, but not by component B.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ciFor special container components, such as **Stack**, **onTouch** events can be received by parent and child components at the same time, but how they are received by child components depends on the stacking relationship.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci```ts
34e41f4b71Sopenharmony_ciStack A() {
35e41f4b71Sopenharmony_ci    ComponentB().onTouch(() => {})
36e41f4b71Sopenharmony_ci    ComponentC().onTouch(() => {})
37e41f4b71Sopenharmony_ci}.onTouch(() => {})
38e41f4b71Sopenharmony_ci```
39e41f4b71Sopenharmony_ciAssume that components B and C are children of Stack A, and component C is stacked on component B. Then touching component B or component C also touches Stack A. The **onTouch** callback can be invoked by multiple components at the same time. Therefore, when the overlapping area of components B and C is touched, the **onTouch** callback is invoked by both Stack A and component C, but not by component B (which is stacked by component C).
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci### Gestures and Events
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ciAll gestures and events except the touch event (**onTouch**) are implemented using basic or combined gestures. For example, the drag event is a sequence of a long press gesture and a swipe gesture.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ciIf no explicit declaration is made, only one gesture in a gesture group can be recognized for a single finger at the same time, which means that only one set callback can be invoked.
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ciTherefore, unless it is explicitly declared that multiple gestures can be recognized at the same time, only one gesture is handled at once.
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ciThe response to gestures complies with the following rules:
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci1. When the parent and child components are bound to the same type of gesture, the child component responds prior to the parent component.
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci2. When a component is bound to multiple gestures, the gesture that first meets triggering conditions is preferentially triggered.
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci```ts
56e41f4b71Sopenharmony_ciComponentA() {
57e41f4b71Sopenharmony_ci    ComponentB().gesture(TapGesture({count: 1}))
58e41f4b71Sopenharmony_ci}.gesture(TapGesture({count: 1}))    
59e41f4b71Sopenharmony_ci```
60e41f4b71Sopenharmony_ciWhen both the parent and child components are bound to a tap gesture, the child component responds prior to the parent component.
61e41f4b71Sopenharmony_ciTherefore, when the user touches component B, the callback of **TapGesture** bound to component B is invoked, but the callback bound to component A is not.
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci```ts
64e41f4b71Sopenharmony_ciComponentA()
65e41f4b71Sopenharmony_ci.gesture(
66e41f4b71Sopenharmony_ci    GestureGroup(
67e41f4b71Sopenharmony_ci        GestureMode.Exclusive,
68e41f4b71Sopenharmony_ci        TapGesture({count: 1}),
69e41f4b71Sopenharmony_ci        PanGesture({distance: 5})
70e41f4b71Sopenharmony_ci    )
71e41f4b71Sopenharmony_ci)
72e41f4b71Sopenharmony_ci```
73e41f4b71Sopenharmony_ciIf the tap gesture and the swipe gesture are bound to a component in exclusive recognition mode, the gesture that first meets triggering conditions is preferentially triggered.
74e41f4b71Sopenharmony_ciIf the user performs a tap operation, the callback corresponding to the tap is invoked. If the user performs a swipe operation and the swipe distance reaches the threshold, the callback corresponding to the swipe is invoked.
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci## Handling Multi-level Gesture Events with Custom Logic
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ciYou can set attributes to control the multi-level gesture event competition process.
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ciSpecifically, use the **responseRegion** and **hitTestBehavior** attributes to control dispatching of touch events, thereby affecting the response to the **onTouch** events and gestures. You can also call gesture binding methods to control gesture competition and affect gesture response, but this approach does not affect triggering of **onTouch** events.
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci### Using responseRegion
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ciThe **responseRegion** attribute sets the touch target of a component, which can be larger or smaller than the layout scope of the component.
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ci```ts
87e41f4b71Sopenharmony_ciComponentA() {
88e41f4b71Sopenharmony_ci    ComponentB()
89e41f4b71Sopenharmony_ci    .onTouch(() => {})
90e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
91e41f4b71Sopenharmony_ci    .responseRegion({Rect1, Rect2, Rect3})
92e41f4b71Sopenharmony_ci}
93e41f4b71Sopenharmony_ci.onTouch(() => {})
94e41f4b71Sopenharmony_ci.gesture(TapGesture({count: 1}))
95e41f4b71Sopenharmony_ci.responseRegion({Rect4})
96e41f4b71Sopenharmony_ci```
97e41f4b71Sopenharmony_ciIn the preceding example, **.responseRegion({Rect4})** is set for component A, and as such, all touch events and gestures that fall within the Rect4 region can be received by the callback corresponding to component A.
98e41f4b71Sopenharmony_ci
99e41f4b71Sopenharmony_ciSimilarly, with **.responseRegion({Rect1, Rect2, Rect3})** set for component B, all touch events and gestures that fall within the Rect1, Rect2, and Rect3 regions can be received by the callback corresponding to component B.
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_ciWhen **responseRegion** is set for a component, the component responds to all gestures and events that occur within the designated regions, instead of those in the layout area. This may lead to no response to gestures and events in the layout-related area.
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ciThe **responseRegion** attribute accepts an array consisting of multiple **Rect** values.
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci### Using hitTestBehavior
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ciThe **hitTestBehavior** attribute sets which components can respond to specific gestures and events. It is especially useful under complex multi-level event scenarios.
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci```ts
110e41f4b71Sopenharmony_ciComponentA() {
111e41f4b71Sopenharmony_ci    ComponentB()
112e41f4b71Sopenharmony_ci    .onTouch(() => {})
113e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ci    ComponentC() {
116e41f4b71Sopenharmony_ci        ComponentD()
117e41f4b71Sopenharmony_ci        .onTouch(() => {})
118e41f4b71Sopenharmony_ci        .gesture(TapGesture({count: 1}))
119e41f4b71Sopenharmony_ci    }
120e41f4b71Sopenharmony_ci    .onTouch(() => {})
121e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
122e41f4b71Sopenharmony_ci    .hitTestBehavior(HitTestMode.Block)
123e41f4b71Sopenharmony_ci}
124e41f4b71Sopenharmony_ci.onTouch(() => {})
125e41f4b71Sopenharmony_ci.gesture(TapGesture({count: 1}))
126e41f4b71Sopenharmony_ci```
127e41f4b71Sopenharmony_ciWith **HitTestMode.Block**, the node responds to the hit test of a touch event, but its child node and sibling node are blocked from the hit test; as a result, neither the child node nor sibling node can receive the **onTouch** events and gestures.
128e41f4b71Sopenharmony_ci    
129e41f4b71Sopenharmony_ciWhen **hitTestBehavior** is not set for component C, a touch in the target touch of component D triggers the **onTouch** events of components A, C, and D, as well as the tap gesture of component D.
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ciWhen **hitTestBehavior** is set to **HitTestMode.Block** for component C, a touch in the target touch of component D triggers the **onTouch** events of components A and C, but not the **onTouch** event of component D. In addition, because component D is blocked and its tap gesture of the component D cannot be triggered, the tap gesture of component C is triggered.
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ci```ts
134e41f4b71Sopenharmony_ciStack A() {
135e41f4b71Sopenharmony_ci    ComponentB()
136e41f4b71Sopenharmony_ci    .onTouch(() => {})
137e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_ci    ComponentC()
140e41f4b71Sopenharmony_ci    .onTouch(() => {})
141e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
142e41f4b71Sopenharmony_ci    .hitTestBehavior(HitTestMode.Transparent)
143e41f4b71Sopenharmony_ci}
144e41f4b71Sopenharmony_ci.onTouch(() => {})
145e41f4b71Sopenharmony_ci.gesture(TapGesture({count: 1}))
146e41f4b71Sopenharmony_ci```
147e41f4b71Sopenharmony_ciWith **HitTestMode.Transparent**, both the node and its child node respond to the hit test of a touch event, and its sibling node is also considered during the hit test.
148e41f4b71Sopenharmony_ci
149e41f4b71Sopenharmony_ciIf **hitTestBehavior** is not set for component C, when the overlapping area of component B and component C is touched, the **onTouch** events of Stack A and component C are triggered, the touch event of component C is triggered, and neither the **onTouch** event nor tap gesture of component B is triggered.
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ciIf **hitTestBehavior** is set to **HitTestMode.Transparent** for component C, when the overlapping area of components B and C is touched, the **onTouch** events of Stack A and component C are still triggered, and the touch event of component C is also triggered; yet, because component B can receive the touch event in this case, its **onTouch** event and tap gesture are triggered.
152e41f4b71Sopenharmony_ci
153e41f4b71Sopenharmony_ci```ts
154e41f4b71Sopenharmony_ciComponentA() {
155e41f4b71Sopenharmony_ci    ComponentB()
156e41f4b71Sopenharmony_ci    .onTouch(() => {})
157e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
158e41f4b71Sopenharmony_ci}
159e41f4b71Sopenharmony_ci.onTouch(() => {})
160e41f4b71Sopenharmony_ci.gesture(TapGesture({count: 1}))
161e41f4b71Sopenharmony_ci.hitTestBehavior(HitTestMode.None)
162e41f4b71Sopenharmony_ci```
163e41f4b71Sopenharmony_ciWith **HitTestMode.None**, the node does not respond to the hit test of a touch event, but its child node and sibling node are considered during the hit test.
164e41f4b71Sopenharmony_ci
165e41f4b71Sopenharmony_ciIf **hitTestBehavior** is not set for component A, a touch in the target touch of component B triggers the **onTouch** events of components A and B, as well as the tap gesture of component B.
166e41f4b71Sopenharmony_ci
167e41f4b71Sopenharmony_ciWhen **hitTestBehavior** is set to **HitTestMode.None** for component A, a touch in the target touch of component B triggers the **onTouch** event and tap gesture of component B, but not the **onTouch** event of component A.
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ciUnder simple scenarios, you are advised to set **hitTestBehavior** for each single component.
170e41f4b71Sopenharmony_ciUnder complex scenarios, you are advised to set different **hitTestBehavior** values to multiple components to control the dispatching of touch events.
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci### Calling Gesture Binding Methods
173e41f4b71Sopenharmony_ciWhen binding a parent component and a child component to a same gesture, you can assign different response priorities to them by using different gesture binding methods.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ciWhen **.gesture** is used for gesture binding, the child component responds prior to the parent component.
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ci```ts
178e41f4b71Sopenharmony_ciComponentA() {
179e41f4b71Sopenharmony_ci    ComponentB()
180e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
181e41f4b71Sopenharmony_ci}
182e41f4b71Sopenharmony_ci.gesture(TapGesture({count: 1}))
183e41f4b71Sopenharmony_ci```
184e41f4b71Sopenharmony_ciIn the preceding example, both the parent and child components are bound to the tap gesture, and the child component responds prior to the parent component.
185e41f4b71Sopenharmony_ciIn this case, when component B is touched, the tap gesture of component B is triggered, but that of component A is not.
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ciTo enable the parent component to respond prior to the child component, use the **.priorityGesture** method.
188e41f4b71Sopenharmony_ci
189e41f4b71Sopenharmony_ci```ts
190e41f4b71Sopenharmony_ciComponentA() {
191e41f4b71Sopenharmony_ci    ComponentB()
192e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
193e41f4b71Sopenharmony_ci}
194e41f4b71Sopenharmony_ci.priorityGesture(TapGesture({count: 1}))
195e41f4b71Sopenharmony_ci```
196e41f4b71Sopenharmony_ciIn the preceding example, the **.priorityGesture** method is used to bind the parent component to the tap gesture, and the parent component responds prior to the child component.
197e41f4b71Sopenharmony_ciIn this case, when component B is touched, the tap gesture of component A is triggered, but that of component B is not.
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ciTo enable both the parent and child components to respond to a same gesture, use the **.parallelGesture** method in the parent component.
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci```ts
202e41f4b71Sopenharmony_ciComponentA() {
203e41f4b71Sopenharmony_ci    ComponentB()
204e41f4b71Sopenharmony_ci    .gesture(TapGesture({count: 1}))
205e41f4b71Sopenharmony_ci}
206e41f4b71Sopenharmony_ci.parallelGesture(TapGesture({count: 1}))
207e41f4b71Sopenharmony_ci```
208e41f4b71Sopenharmony_ciIn the preceding example, the **.parallelGesture** method is used to bind the parent component to the tap gesture, and both the parent and child components can respond to the bound gesture.
209e41f4b71Sopenharmony_ciIn this case, when component B is touched, both the tap gestures of components A and B are triggered.
210