• 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.|
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
71Enumerates the event dispatch strategies.
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: Setting the Event Dispatch Strategy to FORWARD_COMPETITION
88
89In this example, dragging the blank area below the list allows the list to scroll, and clicking the button will trigger its **onClick** event.
90
91```ts
92// xxx.ets
93import { promptAction } from '@kit.ArkUI';
94
95@Entry
96@Component
97struct ListExample {
98  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
99  @State text: string = 'Button'
100
101  build() {
102    Column() {
103      List({ space: 12, initialIndex: 0 }) {
104        ForEach(this.arr, (item: number) => {
105          ListItem() {
106            Text('Item ' + item)
107              .width('100%')
108              .height(56)
109              .fontSize(16)
110              .textAlign(TextAlign.Start)
111          }.borderRadius(24)
112          .backgroundColor(Color.White)
113          .padding({ left: 12, right: 12 })
114        }, (item: string) => item)
115      }
116      .listDirection(Axis.Vertical)
117      .scrollBar(BarState.Off)
118      .edgeEffect(EdgeEffect.Spring)
119      .onScrollIndex((start: number, end: number) => {
120        console.info('first' + start)
121        console.info('last' + end)
122      })
123      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
124        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
125      })
126      .width('100%')
127      .height('65%')
128      .id('MyList')
129
130      Button(this.text)
131        .width(312)
132        .height(40)
133        .id('Mybutton')
134        .fontSize(16)
135        .fontWeight(FontWeight.Medium)
136        .margin({ top: 80 })
137        .onClick(() => {
138          this.text = 'click the button'
139          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
140        })
141    }
142    .width('100%')
143    .height('100%')
144    .backgroundColor(0xF1F3F5)
145    .justifyContent(FlexAlign.End)
146    .padding({ left: 12, right: 12, bottom: 24 })
147    .onChildTouchTest((touchinfo) => {
148      for (let info of touchinfo) {
149        if (info.id == 'MyList') {
150          return { id: info.id, strategy: TouchTestStrategy.FORWARD_COMPETITION }
151        }
152      }
153      return { strategy: TouchTestStrategy.DEFAULT }
154    })
155  }
156}
157```
158
159![onchildtouchtest](figures/on-child-touch-test-competition.gif)
160
161### Example 2: Setting the Event Dispatch Strategy to FORWARD
162
163In this example, dragging the blank area below the list allows the list to scroll, but clicking the button will not trigger its **onClick** event.
164
165```ts
166// xxx.ets
167import { promptAction } from '@kit.ArkUI';
168
169@Entry
170@Component
171struct ListExample {
172  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
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          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, dragging the blank area below the list will not scroll the list, and clicking the button will trigger its **onClick** event.
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  @State text: string = 'Button'
248
249  build() {
250    Column() {
251      List({ space: 12, initialIndex: 0 }) {
252        ForEach(this.arr, (item: number) => {
253          ListItem() {
254            Text('Item ' + item)
255              .width('100%')
256              .height(56)
257              .fontSize(16)
258              .textAlign(TextAlign.Start)
259          }.borderRadius(24)
260          .backgroundColor(Color.White)
261          .padding({ left: 12, right: 12 })
262        }, (item: string) => item)
263      }
264      .listDirection(Axis.Vertical)
265      .scrollBar(BarState.Off)
266      .edgeEffect(EdgeEffect.Spring)
267      .onScrollIndex((start: number, end: number) => {
268        console.info('first' + start)
269        console.info('last' + end)
270      })
271      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
272        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
273      })
274      .width('100%')
275      .height('65%')
276      .id('MyList')
277
278      Button(this.text)
279        .width(312)
280        .height(40)
281        .id('Mybutton')
282        .fontSize(16)
283        .fontWeight(FontWeight.Medium)
284        .margin({ top: 80 })
285        .onClick(() => {
286          this.text = 'click the button'
287          promptAction.showToast({ message: 'you click the button.', duration: 3000 })
288        })
289    }
290    .width('100%')
291    .height('100%')
292    .backgroundColor(0xF1F3F5)
293    .justifyContent(FlexAlign.End)
294    .padding({ left: 12, right: 12, bottom: 24 })
295    .onChildTouchTest((touchinfo) => {
296      return { strategy: TouchTestStrategy.DEFAULT }
297    })
298  }
299}
300```
301
302![onchildtouchtest](figures/on-child-touch-test-default.gif)
303