• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.<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 distributes events based on the hit status of the current node.|
80| 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.|
81| FORWARD | The specified event is forwarded to a particular child node, and the system no longer distributes the event to other sibling nodes.|
82
83## Example
84
85### Example 1: Setting the Event Dispatch Strategy to FORWARD_COMPETITION
86
87In this example, dragging the blank area below the list allows the list to scroll, and clicking the button will trigger its **onClick** event.
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```
156
157![onchildtouchtest](figures/on-child-touch-test-competition.gif)
158
159### Example 2: Setting the Event Dispatch Strategy to FORWARD
160
161In this example, dragging the blank area below the list allows the list to scroll, but clicking the button will not trigger its **onClick** event.
162
163```ts
164// xxx.ets
165import { promptAction } from '@kit.ArkUI';
166
167@Entry
168@Component
169struct ListExample {
170  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
171  @State text: string = 'Button'
172
173  build() {
174    Column() {
175      List({ space: 12, initialIndex: 0 }) {
176        ForEach(this.arr, (item: number) => {
177          ListItem() {
178            Text('Item ' + item)
179              .width('100%')
180              .height(56)
181              .fontSize(16)
182              .textAlign(TextAlign.Start)
183          }.borderRadius(24)
184          .backgroundColor(Color.White)
185          .padding({ left: 12, right: 12 })
186        }, (item: string) => item)
187      }
188      .listDirection(Axis.Vertical)
189      .scrollBar(BarState.Off)
190      .edgeEffect(EdgeEffect.Spring)
191      .onScrollIndex((start: number, end: number) => {
192        console.info('first' + start)
193        console.info('last' + end)
194      })
195      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
196        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
197      })
198      .width('100%')
199      .height('65%')
200      .id('MyList')
201
202      Button(this.text)
203        .width(312)
204        .height(40)
205        .id('Mybutton')
206        .fontSize(16)
207        .fontWeight(FontWeight.Medium)
208        .margin({ top: 80 })
209        .onClick(() => {
210          this.text = 'click the button'
211          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
212        })
213    }
214    .width('100%')
215    .height('100%')
216    .backgroundColor(0xF1F3F5)
217    .justifyContent(FlexAlign.End)
218    .padding({ left: 12, right: 12, bottom: 24 })
219    .onChildTouchTest((touchinfo) => {
220      for (let info of touchinfo) {
221        if (info.id == 'MyList') {
222          return { id: info.id, strategy: TouchTestStrategy.FORWARD }
223        }
224      }
225      return { strategy: TouchTestStrategy.DEFAULT }
226    })
227  }
228}
229```
230
231![onchildtouchtest](figures/on-child-touch-test-forward.gif)
232
233### Example 3: Setting the Event Dispatch Strategy to DEFAULT
234
235In this example, dragging the blank area below the list will not scroll the list, and clicking the button will trigger its **onClick** event.
236
237```ts
238// xxx.ets
239import { promptAction } from '@kit.ArkUI';
240
241@Entry
242@Component
243struct ListExample {
244  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
245  @State text: string = 'Button'
246
247  build() {
248    Column() {
249      List({ space: 12, initialIndex: 0 }) {
250        ForEach(this.arr, (item: number) => {
251          ListItem() {
252            Text('Item ' + item)
253              .width('100%')
254              .height(56)
255              .fontSize(16)
256              .textAlign(TextAlign.Start)
257          }.borderRadius(24)
258          .backgroundColor(Color.White)
259          .padding({ left: 12, right: 12 })
260        }, (item: string) => item)
261      }
262      .listDirection(Axis.Vertical)
263      .scrollBar(BarState.Off)
264      .edgeEffect(EdgeEffect.Spring)
265      .onScrollIndex((start: number, end: number) => {
266        console.info('first' + start)
267        console.info('last' + end)
268      })
269      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
270        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
271      })
272      .width('100%')
273      .height('65%')
274      .id('MyList')
275
276      Button(this.text)
277        .width(312)
278        .height(40)
279        .id('Mybutton')
280        .fontSize(16)
281        .fontWeight(FontWeight.Medium)
282        .margin({ top: 80 })
283        .onClick(() => {
284          this.text = 'click the button'
285          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
286        })
287    }
288    .width('100%')
289    .height('100%')
290    .backgroundColor(0xF1F3F5)
291    .justifyContent(FlexAlign.End)
292    .padding({ left: 12, right: 12, bottom: 24 })
293    .onChildTouchTest((touchinfo) => {
294      return { strategy: TouchTestStrategy.DEFAULT }
295    })
296  }
297}
298```
299
300![onchildtouchtest](figures/on-child-touch-test-default.gif)
301