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 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 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 304