1# 模态转场 2 3 4模态转场是新的界面覆盖在旧的界面上,旧的界面不消失的一种转场方式。 5 6 7**表1** 模态转场接口 8| 接口 | 说明 | 使用场景 | 9| ---------------------------------------- | ----------------- | ---------------------------------------- | 10| [bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md) | 弹出全屏的模态组件。 | 用于自定义全屏的模态展示界面,结合转场动画和共享元素动画可实现复杂转场动画效果,如缩略图片点击后查看大图。 | 11| [bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md) | 弹出半模态组件。 | 用于半模态展示界面,如分享框。 | 12| [bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | 弹出菜单,点击组件后弹出。 | 需要Menu菜单的场景,如一般应用的“+”号键。 | 13| [bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | 弹出菜单,长按或者右键点击后弹出。 | 长按浮起效果,一般结合拖拽框架使用,如桌面图标长按浮起。 | 14| [bindPopup](../reference/arkui-ts/ts-universal-attributes-popup.md) | 弹出Popup弹框。 | Popup弹框场景,如点击后对某个组件进行临时说明。 | 15| if | 通过if新增或删除组件。 | 用来在某个状态下临时显示一个界面,这种方式的返回导航需要由开发者监听接口实现。 | 16 17 18## 使用bindContentCover构建全屏模态转场效果 19 20[bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md)接口用于为组件绑定全屏模态页面,在组件插入和删除时可通过设置转场参数ModalTransition显示过渡动效。 21 221. 定义全屏模态转场效果[bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md)。 23 242. 定义模态展示界面。 25 26 ```ts 27 // 通过@Builder构建模态展示界面 28 @Builder MyBuilder() { 29 Column() { 30 Text('my model view') 31 } 32 // 通过转场动画实现出现消失转场动画效果,transition需要加在builder下的第一个组件 33 .transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion(0.6, 0.8) })) 34 } 35 ``` 36 373. 通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果。 38 39 ```ts 40 class PresentTmp{ 41 isPresent: boolean = false; 42 set(){ 43 this.isPresent = !this.isPresent; 44 } 45 } 46 // 模态转场控制变量 47 @State isPresent: boolean = false; 48 49 Button('Click to present model view') 50 // 通过选定的模态接口,绑定模态展示界面,ModalTransition是内置的ContentCover转场动画类型,这里选择None代表系统不加默认动画 51 .bindContentCover(this.isPresent, this.MyBuilder, ModalTransition.NONE) 52 .onClick(() => { 53 // 改变状态变量,显示模态界面 54 let setPre:PresentTmp = new PresentTmp() 55 setPre.set() 56 }) 57 ``` 58 59 60完整示例代码和效果如下。 61 62 63 64```ts 65import curves from '@ohos.curves'; 66 67@Entry 68@Component 69struct BindContentCoverDemo { 70 // 第一步:定义全屏模态转场效果bindContentCover 71 // 模态转场控制变量 72 @State isPresent: boolean = false; 73 74 // 第二步:定义模态展示界面 75 // 通过@Builder构建模态展示界面 76 @Builder MyBuilder() { 77 Column() { 78 Column() { 79 Column() { 80 Text('back') 81 .fontSize(24) 82 .fontColor(Color.White) 83 } 84 .justifyContent(FlexAlign.Center) 85 .width(100) 86 .height(100) 87 .borderRadius(5) 88 .backgroundColor(0xf56c6c) 89 .onClick(() => { 90 this.isPresent = false; 91 }) 92 } 93 .height('100%') 94 .width('100%') 95 .backgroundColor(0x909399) 96 .justifyContent(FlexAlign.Center) 97 .border({ 98 radius: { 99 topLeft: 15, 100 topRight: 15, 101 } 102 }) 103 } 104 .height('100%') 105 .justifyContent(FlexAlign.End) 106 // 通过转场动画实现出现消失转场动画效果 107 .transition(TransitionEffect.translate({ y: 1000 }).animation({ curve: curves.springMotion(0.6, 0.8) })) 108 } 109 110 build() { 111 Column() { 112 Column() { 113 Text('Click Me') 114 .fontSize(24) 115 .fontColor(Color.White) 116 } 117 // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果 118 .onClick(() => { 119 // 改变状态变量,显示模态界面 120 this.isPresent = !this.isPresent; 121 }) 122 // 通过选定的模态接口,绑定模态展示界面,ModalTransition是内置的ContentCover转场动画类型,这里选择DEFAULT代表设置上下切换动画效果。 123 .bindContentCover(this.isPresent, this.MyBuilder(), ModalTransition.DEFAULT) 124 .justifyContent(FlexAlign.Center) 125 .backgroundColor(0XF56C6C) 126 .width(100) 127 .height(100) 128 .borderRadius(5) 129 } 130 .justifyContent(FlexAlign.Center) 131 .width('100%') 132 .height('100%') 133 } 134} 135``` 136 137 138 139 140 141 142 143## 使用bindSheet构建半模态转场效果 144 145[bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md)属性可为组件绑定半模态页面,在组件插入时可通过设置自定义或默认的内置高度确定半模态大小。构建半模态转场动效的步骤基本与使用bindContentCover构建全屏模态转场动效相同。 146 147完整示例和效果如下。 148 149 150```ts 151@Entry 152@Component 153struct BindSheetDemo { 154 155 // 半模态转场高度控制变量 156 @State sheetHeight: number|SheetSize|null|undefined = 300; 157 // 半模态转场控制条控制变量 158 @State showDragBar: boolean = true; 159 160 // 通过@Builder构建半模态展示界面 161 @Builder myBuilder() { 162 Column() { 163 Button("change height") 164 .margin(10) 165 .fontSize(20) 166 .onClick(() => { 167 this.sheetHeight = 500; 168 }) 169 170 Button("Set Illegal height") 171 .margin(10) 172 .fontSize(20) 173 .onClick(() => { 174 this.sheetHeight = null; 175 }) 176 177 Button("close dragbar") 178 .margin(10) 179 .fontSize(20) 180 .onClick(() => { 181 this.showDragBar = !this.showDragBar; 182 }) 183 Button("close modal 1") 184 .margin(10) 185 .fontSize(20) 186 .onClick(() => { 187 this.isPresent = false; 188 }) 189 } 190 .width('100%') 191 .height('100%') 192 } 193 194 // 半模态转场控制变量 195 @State isPresent: boolean = false; 196 197 build() { 198 Column() { 199 if(this.sheetHeight){ 200 Button("Click to present sheet view") 201 .onClick(() => { 202 // 改变状态变量,让模态界面显示 203 this.isPresent = !this.isPresent; 204 }) 205 .fontSize(20) 206 .margin(10) 207 // 通过选定的半模态接口,绑定模态展示界面,style中包含两个参数,一个是设置半模态的高度,不设置时默认高度是Large,一个是是否显示控制条DragBar,默认是true显示控制条 208 .bindSheet(this.isPresent, this.myBuilder(), { height: this.sheetHeight, dragBar: this.showDragBar }) 209 } 210 } 211 .justifyContent(FlexAlign.Center) 212 .width('100%') 213 .height('100%') 214 } 215} 216``` 217 218 219 220 221## 使用bindMenu实现菜单弹出效果 222 223[bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md)为组件绑定弹出式菜单,通过点击触发。完整示例和效果如下。 224 225 226```ts 227class BMD{ 228 value:ResourceStr = '' 229 action:() => void = () => {} 230} 231@Entry 232@Component 233struct BindMenuDemo { 234 235 // 第一步: 定义一组数据用来表示菜单按钮项 236 @State items:BMD[] = [ 237 { 238 value: '菜单项1', 239 action: () => { 240 console.info('handle Menu1 select') 241 } 242 }, 243 { 244 value: '菜单项2', 245 action: () => { 246 console.info('handle Menu2 select') 247 } 248 }, 249 ] 250 251 build() { 252 Column() { 253 Button('click') 254 .backgroundColor(0x409eff) 255 .borderRadius(5) 256 // 第二步: 通过bindMenu接口将菜单数据绑定给元素 257 .bindMenu(this.items) 258 } 259 .justifyContent(FlexAlign.Center) 260 .width('100%') 261 .height(437) 262 } 263} 264``` 265 266 267 268 269## 使用bindContextMenu实现菜单弹出效果 270 271[bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md)为组件绑定弹出式菜单,通过长按或右键点击触发。完整示例和效果如下。 272 273完整示例和效果如下。 274 275 276```ts 277@Entry 278@Component 279struct BindContextMenuDemo { 280 private num: number[] = [1, 2, 3, 4]; 281 private colors: Color[] = [0x67C23A, 0xE6A23C, 0xf56c6c, 0x909399]; 282 // 通过@Builder构建自定义菜单项 283 @Builder MyMenu() { 284 Row() { 285 Column() { 286 ForEach(this.num, (item: number, index: number = 0) => { 287 Row() { 288 Text(item.toString()) 289 .fontSize(20) 290 .fontColor(Color.White) 291 } 292 .backgroundColor(this.colors[index]) 293 .width('100%') 294 .aspectRatio(2) 295 .justifyContent(FlexAlign.Center) 296 }) 297 } 298 .width('100%') 299 } 300 .width(150) 301 .justifyContent(FlexAlign.Center) 302 .padding(5) 303 } 304 305 build() { 306 Column() { 307 Column() { 308 Text('longPress') 309 .fontSize(20) 310 .fontColor(Color.White) 311 } 312 .justifyContent(FlexAlign.Center) 313 .width(170) 314 .height(50) 315 .bindContextMenu(this.MyMenu, ResponseType.LongPress) 316 .backgroundColor(0xf56c6c) 317 .borderRadius(5) 318 } 319 .justifyContent(FlexAlign.Center) 320 .width('100%') 321 .height(437) 322 } 323} 324``` 325 326 327 328 329## 使用bindPopUp实现气泡弹窗效果 330 331[bindpopup](../reference/arkui-ts/ts-universal-attributes-popup.md)属性可为组件绑定弹窗,并设置弹窗内容,交互逻辑和显示状态。 332 333完整示例和代码如下。 334 335 336```ts 337@Entry 338@Component 339struct BindPopupDemo { 340 341 // 第一步:定义变量控制弹窗显示 342 @State customPopup: boolean = false; 343 344 // 第二步:popup构造器定义弹框内容 345 @Builder popupBuilder() { 346 Column({ space: 2 }) { 347 Row().width(64) 348 .height(64) 349 .backgroundColor(0x409eff) 350 Text('Popup') 351 .fontSize(10) 352 .fontColor(Color.White) 353 } 354 .justifyContent(FlexAlign.SpaceAround) 355 .width(100) 356 .height(100) 357 .padding(5) 358 } 359 360 build() { 361 Column() { 362 363 Button('click') 364 // 第四步:创建点击事件,控制弹窗显隐 365 .onClick(() => { 366 this.customPopup = !this.customPopup; 367 }) 368 .backgroundColor(0xf56c6c) 369 // 第三步:使用bindPopup接口将弹窗内容绑定给元素 370 .bindPopup(this.customPopup, { 371 builder: this.popupBuilder, 372 placement: Placement.Top, 373 maskColor: 0x33000000, 374 popupColor: 0xf56c6c, 375 enableArrow: true, 376 onStateChange: (e) => { 377 if (!e.isVisible) { 378 this.customPopup = false; 379 } 380 } 381 }) 382 } 383 .justifyContent(FlexAlign.Center) 384 .width('100%') 385 .height(437) 386 } 387} 388``` 389 390 391 392 393 394 395## 使用if实现模态转场 396 397上述模态转场接口需要绑定到其他组件上,通过监听状态变量改变调起模态界面。同时,也可以通过if范式,通过新增/删除组件实现模态转场效果。 398 399完整示例和代码如下。 400 401 402```ts 403@Entry 404@Component 405struct ModalTransition1 { 406 407 // 第一步:定义状态变量控制页面显示 408 @State isShow: boolean = false; 409 410 build() { 411 // 第二步:定义Stack布局显示当前页面和模态页面 412 Stack() { 413 Column() { 414 Text('Page1') 415 .fontSize(40) 416 .fontColor(Color.White) 417 .fontWeight(FontWeight.Bolder) 418 419 Text('Click to transition') 420 .fontSize(15) 421 .fontColor(Color.White) 422 } 423 .justifyContent(FlexAlign.Center) 424 .width('100%') 425 .height('100%') 426 .linearGradient({ 427 colors: [ 428 [0xf56c6c, 0.0], 429 [0xffffff, 1.0] 430 ] 431 }) 432 // 第五步:改变状态变量,显示模态页面 433 .onClick(() => { 434 animateTo({ duration: 500 }, () => { 435 this.isShow = !this.isShow; 436 }) 437 }) 438 439 // 第三步:在if中定义模态页面,显示在最上层,通过if控制模态页面出现消失 440 if (this.isShow) { 441 Column() { 442 Text('Page2') 443 .fontSize(40) 444 .fontColor(Color.Gray) 445 .fontWeight(FontWeight.Bolder) 446 447 Text('Click to transition') 448 .fontSize(15) 449 .fontColor(Color.Gray) 450 } 451 .justifyContent(FlexAlign.Start) 452 .width('100%') 453 .height('100%') 454 .linearGradient({ 455 colors: [ 456 [0xffffff, 0.0], 457 [0x409eff, 1.0] 458 ] 459 }) 460 // 第四步:定义模态页面出现消失转场方式 461 .transition(TransitionEffect.OPACITY.combine(TransitionEffect.rotate({ angle: 90, y: 1 }))) 462 .onClick(() => { 463 animateTo({ duration: 500 }, () => { 464 this.isShow = !this.isShow; 465 }) 466 }) 467 } 468 469 } 470 .width('100%') 471 .height('100%') 472 } 473} 474``` 475 476 477