1# ArkUI动画/交互事件开发常见问题(ArkTS) 2 3 4## 焦点事件onBlur/onFocus回调无法触发(API 9) 5 6**问题现象** 7 8焦点事件onBlur/onFocus回调无法触发 9 10**解决措施** 11 12焦点事件默认情况下需要外接键盘的Tab键,或方向键触发,点击触发焦点事件需要添加焦点控制属性focusOnTouch。 13 14**参考链接** 15 16[焦点控制](../reference/apis-arkui/arkui-ts/ts-universal-attributes-focus.md) 17 18 19## scroll里面套一个grid,如何禁用grid的滑动事件(API 9) 20 21可以通过onScrollFrameBegin事件和scrollBy方法实现容器嵌套滚动。 22 23**参考链接** 24 25[容器嵌套滚动样例](../reference/apis-arkui/arkui-ts/ts-container-scroll.md#示例2) 26 27 28## 如何实现一个组件不停地旋转(API 9) 29 30可以通过[属性动画](../reference/apis-arkui/arkui-ts/ts-animatorproperty.md)的方式实现。 31 32 33## 列表目前无法键盘上下滑动,是否能力不支持(API 9) 34 35**解决措施** 36 37有以下两种方案: 38 391. 需要在列表子项中添加focusable(true)进行获焦。 40 412. 在每个item的外层嵌套一个可获焦组件,例如Button。 42 43 44## 键盘移动焦点对象按下enter,为什么不会触发点击事件(API 9) 45 46组件的内置的点击事件和开发者自定义的onClick点击事件默认会和空格键绑定,并非与enter键绑定(UX规格)。 47 48 49## 多层组件嵌套button,如何阻止事件传递(API 9) 50 51可以通过将button组件绑定参数stopPropagation来控制冒泡传递。 52 53 54## 使用router或Navigator实现页面跳转时,如何关闭页面间转场动效(API 9) 55 561. 参考[页面间转场示例](../reference/apis-arkui/arkui-ts/ts-page-transition-animation.md#示例)在当前页面和目标页面中定义pageTransition方法。 57 582. 将页面入场组件PageTransitionEnter和页面退场组件PageTransitionExit的动效参数duration都设置为0。 59 60 61## 在容器组件嵌套的场景下,如何解决手势拖拽事件出现错乱的问题(API 9) 62 63PanGesture用于触发拖动手势事件,滑动的最小距离distance默认为5vp时拖动手势识别成功。可以将distance值设为1,使拖动更灵敏,避免造成事件错乱。 64 65**参考链接** 66 67[PanGesture](../reference/apis-arkui/arkui-ts/ts-basic-gestures-pangesture.md) 68 69 70## 是否支持使用fontFamily属性设置不同的字体(API 9) 71 72默认字体'HarmonyOS Sans',且当前只支持这种字体。 73 74 75## 点击输入框时会拉起软键盘,点击button时软键盘关闭要如何实现(API 9) 76 77TextInput获取焦点会弹出输入法,失去焦点就会关闭软键盘,使用focusControl控制焦点即可关闭软键盘。 78 79**代码示例** 80 81``` 82build() { 83 Column() { 84 TextInput() 85 Button(`hide`) 86 .key('button') 87 .onClick(()=>{ 88 focusControl.requestFocus('button') 89 }) 90 } 91} 92``` 93 94 95## 当父组件绑定了onTouch,其子组件Button绑定了onClick,如何做到点击Button只响应Button的onClick,而不用响应父组件的onTouch(API 9) 96 97可以在Button组件中绑定onTouch,并在onTouch中使用stopPropagation()阻止onTouch冒泡传递到父组件阻止冒泡传递。 98 99**代码示例** 100 101``` 102build() { 103 Row() { 104 Button("点击我") 105 .width(100) 106 .width(100) 107 .backgroundColor('#f00') 108 .onClick(()=>{ 109 console.log("Button onClick") 110 }) 111 .onTouch((e) => { 112 console.log("Button onTouch") 113 e.stopPropagation() 114 }) 115 } 116 .onTouch(() => { 117 console.log("Row onTouch") 118 }) 119} 120``` 121 122 123## 绑定菜单后无法使用右键触发菜单(API 9) 124 125**解决措施** 126 127目前菜单仅支持点击、长按触发方式,没有右键方式。 128 129 130## 点击文本输入框,如何屏蔽系统默认键盘弹起行为(API 9) 131 132设置TextInput组件的focusable属性为false,此组件则不可获焦,就不会拉起系统默认的键盘。 133 134 135## 如何实现上下切换的页面间跳转动画(API 9) 136 137**问题现象** 138 139页面切换时如何实现上下切换动画 140 141**解决措施** 142 143可以使用pageTransition函数来实现页面转场效果,通过PageTransitionEnter和PageTransitionExit指定页面进入和退出的动画效果,将其slide属性设置为SlideEffect.Bottom,则页面入场时从下边划入,出场时滑出到下边,即可实现上下切换效果。 144 145**代码示例** 146 147``` 148// Index.ets 149@Entry 150@Component 151struct PageTransition1 { 152 build() { 153 Stack({alignContent: Alignment.Bottom}) { 154 Navigator({ target: 'pages/Page1'}) { 155 Image($r('app.media.ic_banner01')).width('100%').height(200) // 图片存放在media文件夹下 156 } 157 }.height('100%').width('100%') 158 } 159 pageTransition() { 160 PageTransitionEnter({ duration: 500, curve: Curve.Linear }).slide(SlideEffect.Bottom) 161 PageTransitionExit({ duration: 500, curve: Curve.Ease }).slide(SlideEffect.Bottom) 162 } 163} 164``` 165 166``` 167// Page1.ets 168@Entry 169@Component 170struct PageTransition2 { 171 build() { 172 Stack({alignContent: Alignment.Bottom}) { 173 Navigator({ target: 'pages/Index'}) { 174 Image($r('app.media.ic_banner02')).width('100%').height(200) // 图片存放在media文件夹下 175 } 176 }.height('100%').width('100%') 177 } 178 pageTransition() { 179 PageTransitionEnter({ duration: 500, curve: Curve.Linear }).slide(SlideEffect.Bottom) 180 PageTransitionExit({ duration: 500, curve: Curve.Ease }).slide(SlideEffect.Bottom) 181 } 182} 183``` 184 185**参考链接** 186 187[页面间转场](../reference/apis-arkui/arkui-ts/ts-page-transition-animation.md) 188 189## 自定义组件间如何实现从底部滑入滑出的效果(API 9) 190 191**问题现象** 192 193一个页面底部默认显示自定义组件A,点击自定义组件A,则A消失,自定义组件B从底部出现;点击自定义组件B,则组件B消失,A从底部出现。这个效果要如何实现? 194 195**解决措施** 196 197可以使用transition产生组件转场动画,其参数type用来设置组件变化场景,包括新增和删除;参数translate用来设置转场时的平移效果。注意transition需要配合animateTo才能生效,动效时长、曲线、延时跟随animateTo中的配置。 198 199**代码示例** 200 201``` 202@Entry 203@Component 204struct ComponentTransition { 205 @State flag: boolean = true; 206 207 build() { 208 Stack({alignContent: Alignment.Bottom}) { 209 if (this.flag) { 210 ComponentChild1({ flag: $flag }) 211 .transition({ type: TransitionType.Insert,translate: { x: 0, y: 200 } }) 212 } 213 if (!this.flag) { 214 ComponentChild2({ flag: $flag }) 215 .transition({ type: TransitionType.Insert, translate: { x: 0, y: 200 } }) 216 } 217 }.height('100%').width('100%') 218 } 219} 220 221@Component 222struct ComponentChild1 { 223 @Link flag: boolean 224 225 build() { 226 Column() { 227 Image($r('app.media.ic_banner01')) 228 .width('100%') 229 .height(200) 230 .onClick(() => { 231 animateTo({ duration: 1000 }, () => { 232 this.flag = !this.flag; 233 }) 234 }) 235 } 236 } 237} 238 239@Component 240struct ComponentChild2 { 241 @Link flag: boolean 242 243 build() { 244 Column() { 245 Image($r('app.media.ic_banner02')) 246 .width('100%') 247 .height(200) 248 .onClick(() => { 249 animateTo({ duration: 1000 }, () => { 250 this.flag = !this.flag; 251 }) 252 }) 253 } 254 } 255} 256``` 257 258**参考链接** 259 260[出现/消失转场](../ui/arkts-enter-exit-transition.md) 261 262 263## 文件管理器短按不响应(API 10) 264 265**问题现象** 266 267短按文件夹图标,如点击时长在200-500ms松手会触发文件管理器点击不响应。 268 269**原因分析** 270 271拖拽手势识别逻辑存在异常分支未处理,短按特定时间段松手会导致手势识别器处于pending状态,不再响应用户输入导致文件管理器出现卡死现象。 272 273**解决措施** 274 275长按文件图标或者空白区域即可恢复。 276 277## 如何自定义处理父子组件间的事件传递(API 10) 278 279**解决措施** 280 2811.系统会基于触摸测试来收集需要响应事件的控件,测试的顺序由父组件向子组件蔓延,后续手势的识别和竞争都基于测试结果进行; 282 2832.应用可通过改变组件上hitTestBehavior的值来改变系统对其的hittest结果; 284 2853.可通过自定义事件和自定义手势判定能力来细化对手势识别和竞争结果的干预。 286 287**参考链接** 288 2891.[hitTestBehavior](../reference/apis-arkui/arkui-ts/ts-universal-attributes-hit-test-behavior.md) 290 2912.[自定义事件分发](../reference/apis-arkui/arkui-ts/ts-universal-attributes-on-child-touch-test.md) 292 2933.[自定义手势判定](../reference/apis-arkui/arkui-ts/ts-gesture-customize-judge.md) 294 295## 如何实现对列表的列表项进行拖动时,其他列表项自动补位和动态排列的效果(API 10) 296 297**解决措施** 298 2991.为列表或宫格项(item)添加拖拽能力,使能draggable,并注册onDragStart; 300 3012.在onDragStart回调中将所拖条目设置visibility为HIDDEN状态; 302 3032.在列表或宫格项(item)上注册onDragMove监听拖起的移动事件; 304 3053.拖动过程中,通过onDragMove的event参数获取到拖拽跟手点坐标; 306 3074.计算跟手点坐标与item中线的距离关系,当重合时,启动挤位动效; 308 3095.Item布局信息可通过componentUtils API获取到; 310 3116.挤位动效通过animateTo来改变datasource里的index,触发list的排序动效; 312 3137.落位动效可通过自定义动效完成。 314 315 **示例代码** 316 317```ts 318// 起拖时记录拖拽item 319 .onDragStart((event?: DragEvent, extraParams?: string) => { 320 this.dragIndex = Number(item.data) 321 this.dragItem = item 322 }) 323 // 进入新的item时执行挤位效果 324 .onDragEnter((event?: DragEvent, extraParams?: string) => { 325 if (Number(item.data) != this.dragIndex) { 326 let current = this.dataSource.findIndex((element) => element.data === this.dragItem.data) 327 let index = this.dataSource.findIndex((element) => element.data === item.data) 328 animateTo({ 329 curve: curves.interpolatingSpring(0, 1, 400, 38) 330 }, () => { 331 this.dataSource.splice(current, 1) 332 this.dataSource.splice(index, 0, this.dragItem) 333 }) 334 } 335 }) 336 // 释放时自定义落位动效,在释放位置开始对dragItem执行动效 337 .onDrop((dragEvent: DragEvent) => { 338 dragEvent.useCustomDropAnimation = true; 339 // 获取到落位位置 340 let downLocation = getInspectorByKey(item.data) 341 let currentLocation = dragEvent.getPreviewRect() 342 this.dragItem.scale = 1.05 343 animateTo({ 344 curve: curves.interpolatingSpring(14, 1, 170, 17) 345 }, () => { 346 this.dragItem.scale = 1 347 }) 348 }) 349``` 350