# Custom Event Dispatch
When 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).
> **NOTE**
>
> - 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.
>
> - With use of **onChildTouchTest**, the **onClick**, rotation, and pinch gesture events may receive no response due to the touch target not being hit.
## onChildTouchTest
onChildTouchTest(event: (value: Array<TouchTestInfo>) => TouchResult): T
Allows the current component to customize the hit test and control child component behavior during the test by setting a callback.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters**
| Name| Type | Mandatory| Description |
| ------ | ------------------------------------------ | ---- | ---------------------- |
| value | Array<[TouchTestInfo>](#touchtestinfo) | Yes | Array of child node information.|
**Return value**
| Type| Description|
| -------- | -------- |
| T | Current component.|
>**NOTE**
>
>The array of child node information only includes information about named nodes, that is, nodes for which the **id** attribute is explicitly set.
## TouchTestInfo
Provides information about the coordinate system, ID, and size of the component where the current touch point is located.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
| Name | Type | Description |
| ------------- | ------ | ---------------------------------------- |
| windowX | number | X coordinate of the touch point relative to the upper left corner of the window.
Unit: vp.|
| windowY | number |Y coordinate of the touch point relative to the upper left corner of the window.
Unit: vp.|
| parentX | number |X coordinate of the touch point relative to the upper left corner of the parent component.
Unit: vp. |
| parentY | number |Y coordinate of the touch point relative to the upper left corner of the parent component.
Unit: vp. |
| x | number | X coordinate of the touch point relative to the upper left corner of the child component.
Unit: vp.|
| y | number | Y coordinate of the touch point relative to the upper left corner of the child component.
Unit: vp.|
| rect | [RectResult](ts-types.md#rectresult10) |Size of the child component. |
| [id](ts-universal-attributes-component-id.md) | string | Component ID.|
## TouchResult
Defines the custom event dispatch result. You can influence event dispatch by returning specific results.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
| Name | Type | Mandatory | Description |
| --------- | --------- | ---- |--------------------------------------- |
| strategy | [TouchTestStrategy](#touchteststrategy) | Yes | Event dispatch strategy. |
| id | string | No | Component ID.
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.|
## TouchTestStrategy
Enumerates the event dispatch strategies.
**Atomic service API**: This API can be used in atomic services since API version 12.
**System capability**: SystemCapability.ArkUI.ArkUI.Full
| Name | Description |
| ------------| ----------------------------------------- |
| DEFAULT | Custom dispatch has no effect; the system dispatches events based on the hit status of the current node.|
| FORWARD_COMPETITION | The event is dispatched to a specified child node, and the system determines whether to dispatch events to other sibling nodes.|
| FORWARD | The event is dispatched to a specified child node, and the system will not dispatch events to other sibling nodes.|
## Example
### Example 1: Setting the Event Dispatch Strategy to FORWARD_COMPETITION
In 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.
```ts
// xxx.ets
import { PromptAction } from '@kit.ArkUI';
@Entry
@Component
struct ListExample {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
promptAction: PromptAction = this.getUIContext().getPromptAction();
@State text: string = 'Button'
build() {
Column() {
List({ space: 12, initialIndex: 0 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('Item ' + item)
.width('100%')
.height(56)
.fontSize(16)
.textAlign(TextAlign.Start)
}.borderRadius(24)
.backgroundColor(Color.White)
.padding({ left: 12, right: 12 })
}, (item: string) => item)
}
.listDirection(Axis.Vertical)
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.Spring)
.onScrollIndex((start: number, end: number) => {
console.info('first' + start)
console.info('last' + end)
})
.onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
})
.width('100%')
.height('65%')
.id('MyList')
Button(this.text)
.width(312)
.height(40)
.id('Mybutton')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ top: 80 })
.onClick(() => {
this.text = 'click the button'
this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
})
}
.width('100%')
.height('100%')
.backgroundColor(0xF1F3F5)
.justifyContent(FlexAlign.End)
.padding({ left: 12, right: 12, bottom: 24 })
.onChildTouchTest((touchinfo) => {
for (let info of touchinfo) {
if (info.id == 'MyList') {
return { id: info.id, strategy: TouchTestStrategy.FORWARD_COMPETITION }
}
}
return { strategy: TouchTestStrategy.DEFAULT }
})
}
}
```

### Example 2: Setting the Event Dispatch Strategy to FORWARD
In 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.
```ts
// xxx.ets
import { PromptAction } from '@kit.ArkUI';
@Entry
@Component
struct ListExample {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
promptAction: PromptAction = this.getUIContext().getPromptAction();
@State text: string = 'Button'
build() {
Column() {
List({ space: 12, initialIndex: 0 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('Item ' + item)
.width('100%')
.height(56)
.fontSize(16)
.textAlign(TextAlign.Start)
}.borderRadius(24)
.backgroundColor(Color.White)
.padding({ left: 12, right: 12 })
}, (item: string) => item)
}
.listDirection(Axis.Vertical)
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.Spring)
.onScrollIndex((start: number, end: number) => {
console.info('first' + start)
console.info('last' + end)
})
.onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
})
.width('100%')
.height('65%')
.id('MyList')
Button(this.text)
.width(312)
.height(40)
.id('Mybutton')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ top: 80 })
.onClick(() => {
this.text = 'click the button'
this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
})
}
.width('100%')
.height('100%')
.backgroundColor(0xF1F3F5)
.justifyContent(FlexAlign.End)
.padding({ left: 12, right: 12, bottom: 24 })
.onChildTouchTest((touchinfo) => {
for (let info of touchinfo) {
if (info.id == 'MyList') {
return { id: info.id, strategy: TouchTestStrategy.FORWARD }
}
}
return { strategy: TouchTestStrategy.DEFAULT }
})
}
}
```

### Example 3: Setting the Event Dispatch Strategy to DEFAULT
In 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.
```ts
// xxx.ets
import { PromptAction } from '@kit.ArkUI';
@Entry
@Component
struct ListExample {
private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
promptAction: PromptAction = this.getUIContext().getPromptAction();
@State text: string = 'Button'
build() {
Column() {
List({ space: 12, initialIndex: 0 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text('Item ' + item)
.width('100%')
.height(56)
.fontSize(16)
.textAlign(TextAlign.Start)
}.borderRadius(24)
.backgroundColor(Color.White)
.padding({ left: 12, right: 12 })
}, (item: string) => item)
}
.listDirection(Axis.Vertical)
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.Spring)
.onScrollIndex((start: number, end: number) => {
console.info('first' + start)
console.info('last' + end)
})
.onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
})
.width('100%')
.height('65%')
.id('MyList')
Button(this.text)
.width(312)
.height(40)
.id('Mybutton')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ top: 80 })
.onClick(() => {
this.text = 'click the button'
this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
})
}
.width('100%')
.height('100%')
.backgroundColor(0xF1F3F5)
.justifyContent(FlexAlign.End)
.padding({ left: 12, right: 12, bottom: 24 })
.onChildTouchTest((touchinfo) => {
return { strategy: TouchTestStrategy.DEFAULT }
})
}
}
```
