• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Custom Event Dispatch
2
3When handling a touch event, ArkUI performs a hit test on the touch point and the component area before the event is triggered – to determine the components targeted by the event – and dispatches the event based on the test result. You can use **onChildTouchTest** on a parent node to specify how to perform the hit test on child nodes and thereby exert an impact on touch event dispatch. For details about the impact, see [TouchTestStrategy](#touchteststrategy).
4
5>  **NOTE**
6>
7>  - The initial APIs of this module are supported since API version 11. Updates will be marked with a superscript to indicate their earliest API version.
8>
9>  - With use of **onChildTouchTest**, the **onClick**, rotation, and pinch gesture events may receive no response due to the touch target not being hit.
10
11## onChildTouchTest
12
13onChildTouchTest(event: (value: Array<TouchTestInfo>) => TouchResult): T
14
15Allows the current component to customize the hit test and control child component behavior during the test by setting a callback.
16
17**Atomic service API**: This API can be used in atomic services since API version 12.
18
19**System capability**: SystemCapability.ArkUI.ArkUI.Full
20
21**Parameters**
22
23| Name| Type                                      | Mandatory| Description                  |
24| ------ | ------------------------------------------ | ---- | ---------------------- |
25| value  | Array<[TouchTestInfo>](#touchtestinfo) | Yes  | Array of child node information.|
26
27**Return value**
28
29| Type| Description|
30| -------- | -------- |
31| T | Current component.|
32
33>**NOTE**
34>
35>The array of child node information only includes information about named nodes, that is, nodes for which the **id** attribute is explicitly set.
36
37## TouchTestInfo
38
39Provides information about the coordinate system, ID, and size of the component where the current touch point is located.
40
41**Atomic service API**: This API can be used in atomic services since API version 12.
42
43**System capability**: SystemCapability.ArkUI.ArkUI.Full
44
45| Name         | Type  | Description                                      |
46| ------------- | ------ | ---------------------------------------- |
47| windowX | number | X coordinate of the touch point relative to the upper left corner of the window.<br>Unit: vp.|
48| windowY   | number |Y coordinate of the touch point relative to the upper left corner of the window.<br>Unit: vp.|
49| parentX   | number |X coordinate of the touch point relative to the upper left corner of the parent component.<br>Unit: vp. |
50| parentY   | number |Y coordinate of the touch point relative to the upper left corner of the parent component.<br>Unit: vp. |
51| x   | number | X coordinate of the touch point relative to the upper left corner of the child component.<br>Unit: vp.|
52| y   | number | Y coordinate of the touch point relative to the upper left corner of the child component.<br>Unit: vp.|
53| rect   | [RectResult](ts-types.md#rectresult10) |Size of the child component. |
54| [id](ts-universal-attributes-component-id.md)   | string | Component ID.|
55
56## TouchResult
57
58Defines the custom event dispatch result. You can influence event dispatch by returning specific results.
59
60**Atomic service API**: This API can be used in atomic services since API version 12.
61
62**System capability**: SystemCapability.ArkUI.ArkUI.Full
63
64| Name     | Type                                    | Mandatory  | Description                               |
65| --------- | --------- | ---- |--------------------------------------- |
66| strategy  | [TouchTestStrategy](#touchteststrategy) | Yes   | Event dispatch strategy.                    |
67| id  | string | No   | Component ID.<br>If **strategy** is set to **TouchTestStrategy.DEFAULT**, **id** is optional. If **strategy** is set to **TouchTestStrategy.FORWARD_COMPETITION** or **TouchTestStrategy.FORWARD**, **id** is mandatory. If **id** is not returned, the strategy **TouchTestStrategy.DEFAULT** is used.|
68
69## TouchTestStrategy
70
71Enumerates the event dispatch strategies.
72
73**Atomic service API**: This API can be used in atomic services since API version 12.
74
75**System capability**: SystemCapability.ArkUI.ArkUI.Full
76
77| Name         | Description                                      |
78| ------------| ----------------------------------------- |
79| DEFAULT     | Custom dispatch has no effect; the system dispatches events based on the hit status of the current node.|
80| FORWARD_COMPETITION       | The event is dispatched to a specified child node, and the system determines whether to dispatch events to other sibling nodes.|
81| FORWARD | The event is dispatched to a specified child node, and the system will not dispatch events to other sibling nodes.|
82
83## Example
84
85### Example 1: Setting the Event Dispatch Strategy to FORWARD_COMPETITION
86
87In this example, clicking and dragging in the blank area below the **List** component causes the **List** component to scroll. The **Button** component still responds to clicks.
88
89```ts
90// xxx.ets
91import { PromptAction } from '@kit.ArkUI';
92
93@Entry
94@Component
95struct ListExample {
96  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
97  promptAction: PromptAction = this.getUIContext().getPromptAction();
98  @State text: string = 'Button'
99
100  build() {
101    Column() {
102      List({ space: 12, initialIndex: 0 }) {
103        ForEach(this.arr, (item: number) => {
104          ListItem() {
105            Text('Item ' + item)
106              .width('100%')
107              .height(56)
108              .fontSize(16)
109              .textAlign(TextAlign.Start)
110          }.borderRadius(24)
111          .backgroundColor(Color.White)
112          .padding({ left: 12, right: 12 })
113        }, (item: string) => item)
114      }
115      .listDirection(Axis.Vertical)
116      .scrollBar(BarState.Off)
117      .edgeEffect(EdgeEffect.Spring)
118      .onScrollIndex((start: number, end: number) => {
119        console.info('first' + start)
120        console.info('last' + end)
121      })
122      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
123        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
124      })
125      .width('100%')
126      .height('65%')
127      .id('MyList')
128
129      Button(this.text)
130        .width(312)
131        .height(40)
132        .id('Mybutton')
133        .fontSize(16)
134        .fontWeight(FontWeight.Medium)
135        .margin({ top: 80 })
136        .onClick(() => {
137          this.text = 'click the button'
138          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
139        })
140    }
141    .width('100%')
142    .height('100%')
143    .backgroundColor(0xF1F3F5)
144    .justifyContent(FlexAlign.End)
145    .padding({ left: 12, right: 12, bottom: 24 })
146    .onChildTouchTest((touchinfo) => {
147      for (let info of touchinfo) {
148        if (info.id == 'MyList') {
149          return { id: info.id, strategy: TouchTestStrategy.FORWARD_COMPETITION }
150        }
151      }
152      return { strategy: TouchTestStrategy.DEFAULT }
153    })
154  }
155}
156```
157
158![onchildtouchtest](figures/on-child-touch-test-competition.gif)
159
160### Example 2: Setting the Event Dispatch Strategy to FORWARD
161
162In this example, clicking and dragging in the blank area below the **List** component causes the **List** component to scroll. The **Button** component does not respond to clicks.
163
164```ts
165// xxx.ets
166import { PromptAction } from '@kit.ArkUI';
167
168@Entry
169@Component
170struct ListExample {
171  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
172  promptAction: PromptAction = this.getUIContext().getPromptAction();
173  @State text: string = 'Button'
174
175  build() {
176    Column() {
177      List({ space: 12, initialIndex: 0 }) {
178        ForEach(this.arr, (item: number) => {
179          ListItem() {
180            Text('Item ' + item)
181              .width('100%')
182              .height(56)
183              .fontSize(16)
184              .textAlign(TextAlign.Start)
185          }.borderRadius(24)
186          .backgroundColor(Color.White)
187          .padding({ left: 12, right: 12 })
188        }, (item: string) => item)
189      }
190      .listDirection(Axis.Vertical)
191      .scrollBar(BarState.Off)
192      .edgeEffect(EdgeEffect.Spring)
193      .onScrollIndex((start: number, end: number) => {
194        console.info('first' + start)
195        console.info('last' + end)
196      })
197      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
198        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
199      })
200      .width('100%')
201      .height('65%')
202      .id('MyList')
203
204      Button(this.text)
205        .width(312)
206        .height(40)
207        .id('Mybutton')
208        .fontSize(16)
209        .fontWeight(FontWeight.Medium)
210        .margin({ top: 80 })
211        .onClick(() => {
212          this.text = 'click the button'
213          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
214        })
215    }
216    .width('100%')
217    .height('100%')
218    .backgroundColor(0xF1F3F5)
219    .justifyContent(FlexAlign.End)
220    .padding({ left: 12, right: 12, bottom: 24 })
221    .onChildTouchTest((touchinfo) => {
222      for (let info of touchinfo) {
223        if (info.id == 'MyList') {
224          return { id: info.id, strategy: TouchTestStrategy.FORWARD }
225        }
226      }
227      return { strategy: TouchTestStrategy.DEFAULT }
228    })
229  }
230}
231```
232
233![onchildtouchtest](figures/on-child-touch-test-forward.gif)
234
235### Example 3: Setting the Event Dispatch Strategy to DEFAULT
236
237In this example, clicking and dragging in the blank area below the **List** component does not cause the **List** component to scroll. The **Button** component responds to clicks.
238
239```ts
240// xxx.ets
241import { PromptAction } from '@kit.ArkUI';
242
243@Entry
244@Component
245struct ListExample {
246  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
247  promptAction: PromptAction = this.getUIContext().getPromptAction();
248  @State text: string = 'Button'
249
250  build() {
251    Column() {
252      List({ space: 12, initialIndex: 0 }) {
253        ForEach(this.arr, (item: number) => {
254          ListItem() {
255            Text('Item ' + item)
256              .width('100%')
257              .height(56)
258              .fontSize(16)
259              .textAlign(TextAlign.Start)
260          }.borderRadius(24)
261          .backgroundColor(Color.White)
262          .padding({ left: 12, right: 12 })
263        }, (item: string) => item)
264      }
265      .listDirection(Axis.Vertical)
266      .scrollBar(BarState.Off)
267      .edgeEffect(EdgeEffect.Spring)
268      .onScrollIndex((start: number, end: number) => {
269        console.info('first' + start)
270        console.info('last' + end)
271      })
272      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
273        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
274      })
275      .width('100%')
276      .height('65%')
277      .id('MyList')
278
279      Button(this.text)
280        .width(312)
281        .height(40)
282        .id('Mybutton')
283        .fontSize(16)
284        .fontWeight(FontWeight.Medium)
285        .margin({ top: 80 })
286        .onClick(() => {
287          this.text = 'click the button'
288          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
289        })
290    }
291    .width('100%')
292    .height('100%')
293    .backgroundColor(0xF1F3F5)
294    .justifyContent(FlexAlign.End)
295    .padding({ left: 12, right: 12, bottom: 24 })
296    .onChildTouchTest((touchinfo) => {
297      return { strategy: TouchTestStrategy.DEFAULT }
298    })
299  }
300}
301```
302
303![onchildtouchtest](figures/on-child-touch-test-default.gif)
304