1# 自定义事件分发 2 3ArkUI在处理触屏事件时,会在触屏事件触发前进行按压点和组件区域的触摸测试,来收集需要响应触屏事件的组件,再基于触摸测试结果分发相应的触屏事件。在父节点,开发者可以通过onChildTouchTest决定如何让子节点去做触摸测试,影响子组件的触摸测试,最终影响后续的触屏事件分发,具体影响参考[TouchTestStrategy](#touchteststrategy枚举说明)枚举说明。 4 5> **说明:** 6> 7> - 从API Version 11开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> 9> - onClick以及旋转、捏合手势经过自定义事件分发之后可能会因为触摸热区没有命中导致事件不响应。 10 11## onChildTouchTest 12 13onChildTouchTest(event: (value: Array<TouchTestInfo>) => TouchResult): T 14 15当前组件可通过设置回调来自定义子节点如何去做触摸测试。 16 17**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 18 19**系统能力:** SystemCapability.ArkUI.ArkUI.Full 20 21**参数:** 22 23| 参数名 | 类型 | 必填 | 说明 | 24| ------ | ------------------------------------------ | ---- | ---------------------- | 25| value | Array<[TouchTestInfo>](#touchtestinfo) | 是 | 包含子节点信息的数组。 | 26 27**返回值:** 28 29| 类型 | 说明 | 30| -------- | -------- | 31| T | 返回当前组件。 | 32 33>**说明:** 34> 35>子节点信息数组中只包含命名节点的信息,即开发者通过id属性设置了id的节点。 36 37## TouchTestInfo 38 39当前按压点所在组件的坐标系、id和尺寸相关信息。 40 41**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 42 43**系统能力:** SystemCapability.ArkUI.ArkUI.Full 44 45| 名称 | 类型 | 描述 | 46| ------------- | ------ | ---------------------------------------- | 47| windowX | number | 按压点相对于窗口左上角的x轴坐标。<br />单位:vp | 48| windowY | number |按压点相对于窗口左上角的y轴坐标。<br />单位:vp| 49| parentX | number |按压点相对于父组件左上角的x轴坐标。<br />单位:vp | 50| parentY | number |按压点相对于父组件左上角的y轴坐标。<br />单位:vp | 51| x | number | 按压点相对于子组件左上角的x轴坐标。<br />单位:vp | 52| y | number | 按压点相对于子组件左上角的y轴坐标。<br />单位:vp | 53| rect | [RectResult](ts-types.md#rectresult10) |子组件的大小。 | 54| [id](ts-universal-attributes-component-id.md) | string | 通过id属性设置的组件id。 | 55 56## TouchResult 57 58自定义事件分发结果,开发者通过返回结果来影响事件分发。 59 60**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 61 62**系统能力:** SystemCapability.ArkUI.ArkUI.Full 63 64| 名称 | 类型 | 必填 | 描述 | 65| --------- | --------- | ---- |--------------------------------------- | 66| strategy | [TouchTestStrategy](#touchteststrategy枚举说明) | 是 | 事件派发策略。 | 67| id | string | 否 | 通过id属性设置的组件id。<br>当strategy为TouchTestStrategy.DEFAULT时,id是可选的;当strategy是TouchTestStrategy.FORWARD_COMPETITION或TouchTestStrategy.FORWARD时,id是必需的(如果没有返回id,则当成TouchTestStrategy.DEFAULT处理)。 | 68 69## TouchTestStrategy枚举说明 70 71事件派发策略。 72 73**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 74 75**系统能力:** SystemCapability.ArkUI.ArkUI.Full 76 77| 名称 | 描述 | 78| ------------| ----------------------------------------- | 79| DEFAULT | 自定义分发不产生影响,系统按当前节点命中状态分发事件。 | 80| FORWARD_COMPETITION | 应用指定分发事件到某个子节点,其他兄弟节点是否分发事件交由系统决定。 | 81| FORWARD | 应用指定分发事件到某个子节点,系统不再处理分发事件到其他兄弟节点。 | 82 83## 示例 84 85### 示例1(设置事件派发策略为FORWARD_COMPETITION) 86 87该示例点击List下方空白区域后拖动,能够拖动List滑动。点击Button按钮,Button会响应onClick事件。 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 158 159### 示例2(设置事件派发策略为FORWARD) 160 161点击List下方空白区域后拖动,能够拖动List滑动。点击Button按钮,Button不会响应onClick事件。 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 232 233### 示例3(设置事件派发策略为DEFAULT) 234 235点击List下方空白区域后拖动,List不会滑动。点击Button按钮,Button会响应onClick事件。 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