arkts-modal-transition.md 13.2 KB
Newer Older
H
HelloCrease 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
# 模态转场


模态转场是新的界面覆盖在旧的界面上,旧的界面不消失的一种转场方式。


  **表1** 模态转场接口

| 接口 | 说明 | 使用场景 |
| -------- | -------- | -------- |
| [bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md#%E5%85%A8%E5%B1%8F%E6%A8%A1%E6%80%81%E8%BD%AC%E5%9C%BA) | 弹出全屏的模态组件。 | 用于自定义全屏的模态展示界面,结合转场动画和共享元素动画可实现复杂转场动画效果,如缩略图片点击后查看大图。 |
| [bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md#%E5%8D%8A%E6%A8%A1%E6%80%81%E8%BD%AC%E5%9C%BA) | 弹出半模态组件。 | 用于半模态展示界面,如分享框。 |
| [bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | 弹出菜单,点击组件后弹出。 | 需要Menu菜单的场景,如一般应用的“+”号键。 |
| [bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md) | 弹出菜单,长按或者右键点击后弹出。 | 长按浮起效果,一般结合拖拽框架使用,如桌面图标长按浮起。 |
| [bindPopup](../reference/arkui-ts/ts-universal-attributes-popup.md) | 弹出Popup弹框。 | Popup弹框场景,如点击后对某个组件进行临时说明。 |
| if | 通过if新增或删除组件。 | 用来在某个状态下临时显示一个界面,这种方式的返回导航需要由开发者监听接口实现。 |


## 使用bindContentCover构建全屏模态转场效果

[bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md#%E5%85%A8%E5%B1%8F%E6%A8%A1%E6%80%81%E8%BD%AC%E5%9C%BA)接口用于为组件绑定全屏模态页面,在组件插入和删除时可通过设置转场参数ModalTransition显示过渡动效。

1. 定义全屏模态转场效果[bindContentCover](../reference/arkui-ts/ts-universal-attributes-modal-transition.md#%E5%85%A8%E5%B1%8F%E6%A8%A1%E6%80%81%E8%BD%AC%E5%9C%BA)

2. 定义模态展示界面。
  
   ```ts
   // 通过@Builder构建模态展示界面
   @Builder MyBuilder() {
     Column() {
       Text('my model view')
     }
     // 通过转场动画实现出现消失转场动画效果,transition需要加在builder下的第一个组件 
     .transition(TransitionEffect.translate(y:300).animation({ curve: curves.springMotion(0.6, 0.8) }))
   }
   ```

3. 通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果。
  
   ```ts
   // 模态转场控制变量
   @State isPresent: boolean = false;
   
   Button('Click to present model view')
     // 通过选定的模态接口,绑定模态展示界面,ModalTransition是内置的ContentCover转场动画类型,这里选择None代表系统不加默认动画
     .bindContentCover($$this.isPresent, this.MyBuilder, ModalTransition.None)
     .onClick(() => {
       // 改变状态变量,让模态界面显示
       this.isPresent = !this.isPresent;
     })
   ```


完整示例代码和效果如下。



```ts
import curves from '@ohos.curves';

@Entry
@Component
struct BindContentCoverDemo {
  // 第一步:定义全屏模态转场效果bindContentCover
  // 模态转场控制变量
  @State isPresent: boolean = false;

  // 第二步:定义模态展示界面
  // 通过@Builder构建模态展示界面
  @Builder MyBuilder() {
    Column() {
      Column() {
        Column() {
          Text('back')
            .fontSize(24)
            .fontColor(Color.White)
        }
        .justifyContent(FlexAlign.Center)
        .width(100)
        .height(100)
        .borderRadius(5)
        .backgroundColor(0xf56c6c)
        .onClick(() => {
          this.isPresent = false;
        })
      }
      .height('100%')
      .width('100%')
      .backgroundColor(0x909399)
      .justifyContent(FlexAlign.Center)
      .border({
        radius: {
          topLeft: 15,
          topRight: 15,
        }
      })
    }
    .height('100%')
    .justifyContent(FlexAlign.End)
    // 通过转场动画实现出现消失转场动画效果
    .transition(TransitionEffect.translate({ y: 1000 }).animation({ curve: curves.springMotion(0.6, 0.8) }))
  }

  build() {
    Column() {
      Column() {
        Text('Click Me')
          .fontSize(24)
          .fontColor(Color.White)
      }
      // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果
      .onClick(() => {
        // 改变状态变量,让模态界面显示
        this.isPresent = !this.isPresent;
      })
      // 通过选定的模态接口,绑定模态展示界面,ModalTransition是内置的ContentCover转场动画类型,这里选择None代表系统不加默认动画
      .bindContentCover($$this.isPresent, this.MyBuilder(), ModalTransition.DEFAULT)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(0XF56C6C)
      .width(100)
      .height(100)
      .borderRadius(5)
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}
```



![zh-cn_image_0000001646921957](figures/zh-cn_image_0000001646921957.gif)



## 使用bindSheet构建半模态转场效果

[bindSheet](../reference/arkui-ts/ts-universal-attributes-sheet-transition.md#%E5%8D%8A%E6%A8%A1%E6%80%81%E8%BD%AC%E5%9C%BA)属性可为组件绑定半模态页面,在组件插入时可通过设置自定义或默认的内置高度确定半模态大小。构建半模态转场动效的步骤基本与使用bindContentCover构建全屏模态转场动效相同。

完整示例和效果如下。


```ts
@Entry
@Component
struct BindSheetDemo {

  // 半模态转场高度控制变量
  @State sheetHeight: number = 300;
  // 半模态转场控制条控制变量
  @State showDragBar: boolean = true;

  // 通过@Builder构建半模态展示界面
  @Builder myBuilder() {
    Column() {
      Button("change height")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.sheetHeight = 500;
        })

      Button("Set Illegal height")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.sheetHeight = null;
        })

      Button("close dragbar")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.showDragBar = !this.showDragBar;
        })
      Button("close modal 1")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.isPresent = false;
        })
    }
    .width('100%')
    .height('100%')
  }

  // 半模态转场控制变量
  @State isPresent: boolean = false;

  build() {
    Column() {
      Button("Click to present sheet view")
        .onClick(() => {
          // 改变状态变量,让模态界面显示
          this.isPresent = !this.isPresent;
        })
        .fontSize(20)
        .margin(10)
          // 通过选定的半模态接口,绑定模态展示界面,style中包含两个参数,一个是设置半模态的高度,不设置时默认高度是Large,一个是是否显示控制条DragBar,默认是true显示控制条
        .bindSheet($$this.isPresent, this.myBuilder(), { height: this.sheetHeight, dragBar: this.showDragBar })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}
```

![zh-cn_image_0000001599977924](figures/zh-cn_image_0000001599977924.gif)


## 使用bindMenu实现菜单弹出效果

[bindMenu](../reference/arkui-ts/ts-universal-attributes-menu.md)为组件绑定弹出式菜单,通过点击触发。完整示例和效果如下。


```ts
@Entry
@Component
struct BindMenuDemo {

  // 第一步: 定义一组数据用来表示菜单按钮项
  private items = [
    {
      value: '菜单项1',
      action: () => {
        console.info('handle Menu1 select')
      }
    },
    {
      value: '菜单项2',
      action: () => {
        console.info('handle Menu2 select')
      }
    },
  ]

  build() {
    Column() {
      Button('click')
        .backgroundColor(0x409eff)
        .borderRadius(5)
          // 第二步: 通过bindMenu接口将菜单数据绑定给元素
        .bindMenu(this.items)
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height(437)
  }
}
```

![zh-cn_image_0000001599643478](figures/zh-cn_image_0000001599643478.gif)


## 使用bindContextMenu实现菜单弹出效果

[bindContextMenu](../reference/arkui-ts/ts-universal-attributes-menu.md)为组件绑定弹出式菜单,通过长按或右键点击触发。完整示例和效果如下。

完整示例和效果如下。


```ts
@Entry
@Component
struct BindContextMenuDemo {
  private num: number[] = [1, 2, 3, 4];
  private colors: Color[] = [0x67C23A, 0xE6A23C, 0xf56c6c, 0x909399];
  // 通过@Builder构建自定义菜单项
  @Builder MyMenu() {
    Row() {
      Column() {
        ForEach(this.num, (item: number, index: number) => {
          Row() {
            Text(item.toString())
              .fontSize(20)
              .fontColor(Color.White)
          }
          .backgroundColor(this.colors[index])
          .width('100%')
          .aspectRatio(2)
          .justifyContent(FlexAlign.Center)
        })
      }
      .width('100%')
    }
    .width(150)
    .justifyContent(FlexAlign.Center)
    .padding(5)
  }

  build() {
    Column() {
      Column() {
        Text('longPress')
          .fontSize(20)
          .fontColor(Color.White)
      }
      .justifyContent(FlexAlign.Center)
      .width(170)
      .height(50)
      .bindContextMenu(this.MyMenu, ResponseType.LongPress)
      .backgroundColor(0xf56c6c)
      .borderRadius(5)
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height(437)
  }
}
```

![zh-cn_image_0000001600137920](figures/zh-cn_image_0000001600137920.gif)


## 使用bindPopUp实现气泡弹窗效果

[bindpopup](../reference/arkui-ts/ts-universal-attributes-popup.md)属性可为组件绑定弹窗,并设置弹窗内容,交互逻辑和显示状态。

完整示例和代码如下。


```ts
@Entry
@Component
struct BindPopupDemo {

  // 第一步:定义变量控制弹窗显示
  @State customPopup: boolean = false;

  // 第二步:popup构造器定义弹框内容
  @Builder popupBuilder() {
    Column({ space: 2 }) {
      Row().width(64)
        .height(64)
        .backgroundColor(0x409eff)
      Text('Popup')
        .fontSize(10)
        .fontColor(Color.White)
    }
    .justifyContent(FlexAlign.SpaceAround)
    .width(100)
    .height(100)
    .padding(5)
  }

  build() {
    Column() {

      Button('click')
        // 第四步:创建点击事件,控制弹窗显隐
        .onClick(() => {
          this.customPopup = !this.customPopup;
        })
        .backgroundColor(0xf56c6c)
          // 第三步:使用bindPopup接口将弹窗内容绑定给元素
        .bindPopup(this.customPopup, {
          builder: this.popupBuilder,
          placement: Placement.Top,
          maskColor: 0x33000000,
          popupColor: 0xf56c6c,
          enableArrow: true,
          onStateChange: (e) => {
            if (!e.isVisible) {
              this.customPopup = false;
            }
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height(437)
  }
}
```



![zh-cn_image_0000001649282285](figures/zh-cn_image_0000001649282285.gif)


## 使用if实现模态转场

上述模态转场接口需要绑定到其他组件上,通过监听状态变量改变调起模态界面。实际上,也可以通过if范式,通过新增/删除组件,实现模态转场效果。

完整示例和代码如下。


```ts
@Entry
@Component
struct ModalTransition1 {

  // 第一步:定义状态变量控制页面显示
  @State isShow: boolean = false;

  build() {
    // 第二步:定义Stack布局显示当前页面和模态页面
    Stack() {
      Column() {
        Text('Page1')
          .fontSize(40)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bolder)

        Text('Click to transition')
          .fontSize(15)
          .fontColor(Color.White)
      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      .linearGradient({
        colors: [
          [0xf56c6c, 0.0],
          [0xffffff, 1.0]
        ]
      })
      // 第五步:改变状态变量,显示模态页面
      .onClick(() => {
        animateTo({ duration: 500 }, () => {
          this.isShow = !this.isShow;
        })
      })

      // 第三步:在if中定义模态页面,显示在最上层,通过if控制模态页面出现消失
      if (this.isShow) {
        Column() {
          Text('Page2')
            .fontSize(40)
            .fontColor(Color.Gray)
            .fontWeight(FontWeight.Bolder)

          Text('Click to transition')
            .fontSize(15)
            .fontColor(Color.Gray)
        }
        .justifyContent(FlexAlign.Start)
        .width('100%')
        .height('100%')
        .linearGradient({
          colors: [
            [0xffffff, 0.0],
            [0x409eff, 1.0]
          ]
        })
        // 第四步:定义模态页面出现消失转场方式
        .transition(TransitionEffect.OPACITY.combine(TransitionEffect.rotate({ angle: 90, y: 1 })))
        .onClick(() => {
          animateTo({ duration: 500 }, () => {
            this.isShow = !this.isShow;
          })
        })
      }

    }
    .width('100%')
    .height('100%')
  }
}
```

![zh-cn_image_0000001597792146](figures/zh-cn_image_0000001597792146.gif)