• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 自定义事件分发
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @jiangtao92-->
5<!--Designer: @piggyguy-->
6<!--Tester: @songyanhong-->
7<!--Adviser: @HelloCrease-->
8
9在处理触屏事件时,ArkUI会在触屏事件触发前进行按压点和组件区域的[触摸测试](../../../ui/arkts-interaction-basic-principles.md#触摸测试),收集需要响应触屏事件的组件,再基于触摸测试结果分发相应的触屏事件。在父节点,可以通过onChildTouchTest决定子节点的触摸测试方式,影响子组件的触摸测试,从而影响后续的触屏事件分发。具体影响参考[TouchTestStrategy](#touchteststrategy11枚举说明)枚举说明。
10
11>  **说明:**
12>
13>  - 从API version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
14>
15>  - onClick和旋转、捏合手势经过自定义事件分发后,可能会因为未命中触摸热区导致事件不响应。
16
17## onChildTouchTest<sup>11+</sup>
18
19onChildTouchTest(event: (value: Array&lt;TouchTestInfo&gt;) => TouchResult): T
20
21当前组件通过设置回调,可自定义触摸测试并控制触摸测试中的子节点行为。
22
23**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
24
25**系统能力:** SystemCapability.ArkUI.ArkUI.Full
26
27**参数:**
28
29| 参数名 | 类型                                       | 必填 | 说明                   |
30| ------ | ------------------------------------------ | ---- | ---------------------- |
31| event  | (value: Array<[TouchTestInfo>](#touchtestinfo11)) => TouchResult | 是   | 触摸事件信息。value的值为包含子节点信息的数组。 |
32
33**返回值:**
34
35| 类型 | 说明 |
36| -------- | -------- |
37| T | 返回当前组件。 |
38
39>**说明:**
40>
41>子节点信息数组中仅包含命名节点的信息,即开发者通过id属性设置了id的节点。
42
43## TouchTestInfo<sup>11+</sup>
44
45当前屏幕触点所在组件的坐标系、id和尺寸相关信息。
46
47**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
48
49**系统能力:** SystemCapability.ArkUI.ArkUI.Full
50
51| 名称          | 类型  | 只读    | 可选   |  说明                                       |
52| ------------- | ------ | ------ | ------ | ---------------------------------------- |
53| windowX | number | 否 | 否| 按压点相对于窗口左上角的x轴坐标。<br />单位:vp |
54| windowY   | number| 否 |否|按压点相对于窗口左上角的y轴坐标。<br />单位:vp|
55| parentX   | number| 否  |否|按压点相对于父组件左上角的x轴坐标。<br />单位:vp  |
56| parentY   | number| 否 |否|按压点相对于父组件左上角的y轴坐标。<br />单位:vp  |
57| x   | number| 否  | 否|按压点相对于子组件左上角的x轴坐标。<br />单位:vp |
58| y   | number| 否  |否| 按压点相对于子组件左上角的y轴坐标。<br />单位:vp |
59| rect   | [RectResult](#rectresult)| 否  |否|子组件的位置和宽高。  |
60| [id](ts-universal-attributes-component-id.md)   | string| 否  | 否|子组件的唯一标识。 |
61
62## RectResult
63
64位置和尺寸类型,用于描述组件的位置和宽高。
65
66**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
67
68**系统能力:** SystemCapability.ArkUI.ArkUI.Full
69
70| 名称      | 类型   | 只读 | 可选  | 说明 |
71| ------- | ------ | ----- | -------- | ---------- |
72| x     | number | 否 | 否 | 水平方向横坐标。|
73| y     | number |  否 | 否 | 竖直方向纵坐标。|
74| width | number | 否 | 否 | 内容宽度大小。|
75| height | number | 否 | 否 | 内容高度大小。|
76
77## TouchResult<sup>11+</sup>
78
79自定义事件分发结果,开发者通过返回结果来影响事件分发。
80
81**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
82
83**系统能力:** SystemCapability.ArkUI.ArkUI.Full
84
85| 名称      | 类型                                     | 只读    | 可选   |  说明                                |
86| --------- | --------- | ---- |--------------------------------------- | ---- |
87| strategy  | [TouchTestStrategy](#touchteststrategy11枚举说明) | 否     | 否  |事件派发策略。                     |
88| id  | string | 否    | 是  |子组件的唯一标识。<br>当strategy为TouchTestStrategy.DEFAULT时,id是可选的;当strategy是TouchTestStrategy.FORWARD_COMPETITIONTouchTestStrategy.FORWARD时,id是必需的(如果没有返回id,则当成TouchTestStrategy.DEFAULT处理)。 |
89
90## TouchTestStrategy<sup>11+</sup>枚举说明
91
92事件派发策略。
93
94**卡片能力:** 从API version 11开始,该接口支持在ArkTS卡片中使用。
95
96**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
97
98**系统能力:** SystemCapability.ArkUI.ArkUI.Full
99
100| 名称          | 值    |说明                                       |
101| ------------| ---------| ----------------------------------------- |
102| DEFAULT   | 0  | 自定义分发不产生影响,系统按当前节点命中状态分发事件。 |
103| FORWARD_COMPETITION  | 1  | 应用指定分发事件到某个子节点,其他兄弟节点是否分发事件交由系统决定。 |
104| FORWARD |2 | 应用指定分发事件到某个子节点,系统不再分发事件到其他兄弟节点。 |
105
106## 示例
107
108### 示例1(设置事件派发策略为FORWARD_COMPETITION)
109
110该示例点击List下方空白区域后拖动,可使List滑动。点击Button按钮时,Button会响应onClick事件。
111
112```ts
113// xxx.ets
114import { PromptAction } from '@kit.ArkUI';
115
116@Entry
117@Component
118struct ListExample {
119  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
120  promptAction: PromptAction = this.getUIContext().getPromptAction();
121  @State text: string = 'Button'
122
123  build() {
124    Column() {
125      List({ space: 12, initialIndex: 0 }) {
126        ForEach(this.arr, (item: number) => {
127          ListItem() {
128            Text('Item ' + item)
129              .width('100%')
130              .height(56)
131              .fontSize(16)
132              .textAlign(TextAlign.Start)
133          }.borderRadius(24)
134          .backgroundColor(Color.White)
135          .padding({ left: 12, right: 12 })
136        }, (item: number) => item.toString())
137      }
138      .listDirection(Axis.Vertical)
139      .scrollBar(BarState.Off)
140      .edgeEffect(EdgeEffect.Spring)
141      .onScrollIndex((start: number, end: number) => {
142        console.info('first' + start)
143        console.info('last' + end)
144      })
145      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
146        console.info(`onScroll scrollState = ScrollState` + scrollState.toString() + `, scrollOffset = ` + scrollOffset)
147      })
148      .width('100%')
149      .height('65%')
150      .id('MyList')
151
152      Button(this.text)
153        .width(312)
154        .height(40)
155        .id('MyButton')
156        .fontSize(16)
157        .fontWeight(FontWeight.Medium)
158        .margin({ top: 80 })
159        .onClick(() => {
160          this.text = 'click the button'
161          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
162        })
163    }
164    .width('100%')
165    .height('100%')
166    .backgroundColor(0xF1F3F5)
167    .justifyContent(FlexAlign.End)
168    .padding({ left: 12, right: 12, bottom: 24 })
169    .onChildTouchTest((touchInfo) => {
170      for (let info of touchInfo) {
171        if (info.id == 'MyList') {
172          return { id: info.id, strategy: TouchTestStrategy.FORWARD_COMPETITION }
173        }
174      }
175      return { strategy: TouchTestStrategy.DEFAULT }
176    })
177  }
178}
179```
180
181![onchildtouchtest](figures/on-child-touch-test-competition.gif)
182
183### 示例2(设置事件派发策略为FORWARD)
184
185点击List下方空白区域后拖动,可以滑动List。点击Button按钮时,Button不会响应onClick事件。
186
187```ts
188// xxx.ets
189import { PromptAction } from '@kit.ArkUI';
190
191@Entry
192@Component
193struct ListExample {
194  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
195  promptAction: PromptAction = this.getUIContext().getPromptAction();
196  @State text: string = 'Button'
197
198  build() {
199    Column() {
200      List({ space: 12, initialIndex: 0 }) {
201        ForEach(this.arr, (item: number) => {
202          ListItem() {
203            Text('Item ' + item)
204              .width('100%')
205              .height(56)
206              .fontSize(16)
207              .textAlign(TextAlign.Start)
208          }.borderRadius(24)
209          .backgroundColor(Color.White)
210          .padding({ left: 12, right: 12 })
211        }, (item: number) => item.toString())
212      }
213      .listDirection(Axis.Vertical)
214      .scrollBar(BarState.Off)
215      .edgeEffect(EdgeEffect.Spring)
216      .onScrollIndex((start: number, end: number) => {
217        console.info('first' + start)
218        console.info('last' + end)
219      })
220      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
221        console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset)
222      })
223      .width('100%')
224      .height('65%')
225      .id('MyList')
226
227      Button(this.text)
228        .width(312)
229        .height(40)
230        .id('MyButton')
231        .fontSize(16)
232        .fontWeight(FontWeight.Medium)
233        .margin({ top: 80 })
234        .onClick(() => {
235          this.text = 'click the button'
236          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
237        })
238    }
239    .width('100%')
240    .height('100%')
241    .backgroundColor(0xF1F3F5)
242    .justifyContent(FlexAlign.End)
243    .padding({ left: 12, right: 12, bottom: 24 })
244    .onChildTouchTest((touchInfo) => {
245      for (let info of touchInfo) {
246        if (info.id == 'MyList') {
247          return { id: info.id, strategy: TouchTestStrategy.FORWARD }
248        }
249      }
250      return { strategy: TouchTestStrategy.DEFAULT }
251    })
252  }
253}
254```
255
256![onchildtouchtest](figures/on-child-touch-test-forward.gif)
257
258### 示例3(设置事件派发策略为DEFAULT)
259
260点击List下方空白区域后拖动,List不会滑动。点击Button按钮时,Button会响应onClick事件。
261
262```ts
263// xxx.ets
264import { PromptAction } from '@kit.ArkUI';
265
266@Entry
267@Component
268struct ListExample {
269  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
270  promptAction: PromptAction = this.getUIContext().getPromptAction();
271  @State text: string = 'Button'
272
273  build() {
274    Column() {
275      List({ space: 12, initialIndex: 0 }) {
276        ForEach(this.arr, (item: number) => {
277          ListItem() {
278            Text('Item ' + item)
279              .width('100%')
280              .height(56)
281              .fontSize(16)
282              .textAlign(TextAlign.Start)
283          }.borderRadius(24)
284          .backgroundColor(Color.White)
285          .padding({ left: 12, right: 12 })
286        }, (item: number) => item.toString())
287      }
288      .listDirection(Axis.Vertical)
289      .scrollBar(BarState.Off)
290      .edgeEffect(EdgeEffect.Spring)
291      .onScrollIndex((start: number, end: number) => {
292        console.info('first' + start)
293        console.info('last' + end)
294      })
295      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
296        console.info(`onScroll scrollState = ScrollState` + scrollState.toString() + `, scrollOffset = ` + scrollOffset)
297      })
298      .width('100%')
299      .height('65%')
300      .id('MyList')
301
302      Button(this.text)
303        .width(312)
304        .height(40)
305        .id('MyButton')
306        .fontSize(16)
307        .fontWeight(FontWeight.Medium)
308        .margin({ top: 80 })
309        .onClick(() => {
310          this.text = 'click the button'
311          this.promptAction.showToast({ message: 'you click the button.', duration: 3000 })
312        })
313    }
314    .width('100%')
315    .height('100%')
316    .backgroundColor(0xF1F3F5)
317    .justifyContent(FlexAlign.End)
318    .padding({ left: 12, right: 12, bottom: 24 })
319    .onChildTouchTest((touchInfo) => {
320      return { strategy: TouchTestStrategy.DEFAULT }
321    })
322  }
323}
324```
325
326![onchildtouchtest](figures/on-child-touch-test-default.gif)