1# Custom Event Dispatch
2
3When handling a touch event, ArkUI performs a touch 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 touch 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>  - This feature is 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
15Called to specify how to perform the touch test on the children of this component.
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 components.|
26
27**Return value**
28
29| Type| Description|
30| -------- | -------- |
31| T | Current component.|
32
33>**NOTE**
34>
35>The array of child components contains only components for which **id** is 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.|
48| windowY   | number |Y coordinate of the touch point relative to the upper left corner of the window.|
49| parentX   | number |X coordinate of the touch point relative to the upper left corner of the parent component. |
50| parentY   | number |Y coordinate of the touch point relative to the upper left corner of the parent component. |
51| x   | number | X coordinate of the touch point relative to the upper left corner of the child component.|
52| y   | number | Y coordinate of the touch point relative to the upper left corner of the child component.|
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
71Describes the event dispatch strategy.
72
73**Widget capability**: This API can be used in ArkTS widgets since API version 11.
74
75**Atomic service API**: This API can be used in atomic services since API version 12.
76
77**System capability**: SystemCapability.ArkUI.ArkUI.Full
78
79| Name         | Description                                      |
80| ------------| ----------------------------------------- |
81| DEFAULT     | Custom dispatch has no effect; the system distributes events based on the hit status of the current node.|
82| FORWARD_COMPETITION       | The specified event is forwarded to a particular child node, and the system determines whether to distribute the event to other sibling nodes.|
83| FORWARD | The specified event is forwarded to a particular child node, and the system no longer distributes the event to other sibling nodes.|
84
85## Example
86
87### Example 1
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  @State text: string = 'Button'
98
99  build() {
100    Column() {
101      List({ space: 12, initialIndex: 0 }) {
102        ForEach(this.arr, (item: number) => {
103          ListItem() {
104            Text('Item ' + item)
105              .width('100%')
106              .height(56)
107              .fontSize(16)
108              .textAlign(TextAlign.Start)
109          }.borderRadius(24)
110          .backgroundColor(Color.White)
111          .padding({ left: 12, right: 12 })
112        }, (item: string) => item)
113      }
114      .listDirection(Axis.Vertical)
115      .scrollBar(BarState.Off)
116      .edgeEffect(EdgeEffect.Spring)
117      .onScrollIndex((start: number, end: number) => {
118        console.info('first' + start)
119        console.info('last' + end)
120      })
121      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
122        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
123      })
124      .width('100%')
125      .height('65%')
126      .id('MyList')
127
128      Button(this.text)
129        .width(312)
130        .height(40)
131        .id('Mybutton')
132        .fontSize(16)
133        .fontWeight(FontWeight.Medium)
134        .margin({ top: 80 })
135        .onClick(() => {
136          this.text = 'click the button'
137          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
138        })
139    }
140    .width('100%')
141    .height('100%')
142    .backgroundColor(0xF1F3F5)
143    .justifyContent(FlexAlign.End)
144    .padding({ left: 12, right: 12, bottom: 24 })
145    .onChildTouchTest((touchinfo) => {
146      for (let info of touchinfo) {
147        if (info.id == 'MyList') {
148          return { id: info.id, strategy: TouchTestStrategy.FORWARD_COMPETITION }
149        }
150      }
151      return { strategy: TouchTestStrategy.DEFAULT }
152    })
153  }
154}
155```
156After you touch the blank area in the lower part of the list and start dragging, the list scrolls. After you touch the button, the **onClick** event is triggered.
157
158![onchildtouchtest](figures/on-child-touch-test-competition.gif)
159
160### Example 2
161
162```ts
163// xxx.ets
164import { promptAction } from '@kit.ArkUI';
165
166@Entry
167@Component
168struct ListExample {
169  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
170  @State text: string = 'Button'
171
172  build() {
173    Column() {
174      List({ space: 12, initialIndex: 0 }) {
175        ForEach(this.arr, (item: number) => {
176          ListItem() {
177            Text('Item ' + item)
178              .width('100%')
179              .height(56)
180              .fontSize(16)
181              .textAlign(TextAlign.Start)
182          }.borderRadius(24)
183          .backgroundColor(Color.White)
184          .padding({ left: 12, right: 12 })
185        }, (item: string) => item)
186      }
187      .listDirection(Axis.Vertical)
188      .scrollBar(BarState.Off)
189      .edgeEffect(EdgeEffect.Spring)
190      .onScrollIndex((start: number, end: number) => {
191        console.info('first' + start)
192        console.info('last' + end)
193      })
194      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
195        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
196      })
197      .width('100%')
198      .height('65%')
199      .id('MyList')
200
201      Button(this.text)
202        .width(312)
203        .height(40)
204        .id('Mybutton')
205        .fontSize(16)
206        .fontWeight(FontWeight.Medium)
207        .margin({ top: 80 })
208        .onClick(() => {
209          this.text = 'click the button'
210          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
211        })
212    }
213    .width('100%')
214    .height('100%')
215    .backgroundColor(0xF1F3F5)
216    .justifyContent(FlexAlign.End)
217    .padding({ left: 12, right: 12, bottom: 24 })
218    .onChildTouchTest((touchinfo) => {
219      for (let info of touchinfo) {
220        if (info.id == 'MyList') {
221          return { id: info.id, strategy: TouchTestStrategy.FORWARD }
222        }
223      }
224      return { strategy: TouchTestStrategy.DEFAULT }
225    })
226  }
227}
228```
229After you touch the blank area in the lower part of the list and start dragging, the list scrolls. After you touch the button, the **onClick** event is not triggered.
230
231![onchildtouchtest](figures/on-child-touch-test-forward.gif)
232
233### Example 3
234
235```ts
236// xxx.ets
237import { promptAction } from '@kit.ArkUI';
238
239@Entry
240@Component
241struct ListExample {
242  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
243  @State text: string = 'Button'
244
245  build() {
246    Column() {
247      List({ space: 12, initialIndex: 0 }) {
248        ForEach(this.arr, (item: number) => {
249          ListItem() {
250            Text('Item ' + item)
251              .width('100%')
252              .height(56)
253              .fontSize(16)
254              .textAlign(TextAlign.Start)
255          }.borderRadius(24)
256          .backgroundColor(Color.White)
257          .padding({ left: 12, right: 12 })
258        }, (item: string) => item)
259      }
260      .listDirection(Axis.Vertical)
261      .scrollBar(BarState.Off)
262      .edgeEffect(EdgeEffect.Spring)
263      .onScrollIndex((start: number, end: number) => {
264        console.info('first' + start)
265        console.info('last' + end)
266      })
267      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
268        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
269      })
270      .width('100%')
271      .height('65%')
272      .id('MyList')
273
274      Button(this.text)
275        .width(312)
276        .height(40)
277        .id('Mybutton')
278        .fontSize(16)
279        .fontWeight(FontWeight.Medium)
280        .margin({ top: 80 })
281        .onClick(() => {
282          this.text = 'click the button'
283          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
284        })
285    }
286    .width('100%')
287    .height('100%')
288    .backgroundColor(0xF1F3F5)
289    .justifyContent(FlexAlign.End)
290    .padding({ left: 12, right: 12, bottom: 24 })
291    .onChildTouchTest((touchinfo) => {
292      return { strategy: TouchTestStrategy.DEFAULT }
293    })
294  }
295}
296```
297After you touch the blank area in the lower part of the list and start dragging, the list does not scroll. After you touch the button, the **onClick** event is triggered.
298
299![onchildtouchtest](figures/on-child-touch-test-default.gif)
300