ArkTS开发系列之导航 (2.7动画)

上篇回顾: ArkTS开发系列之导航 (2.6 图形)

本篇内容:动画的学习使用

一、 知识储备

1. 布局更新动画

  • 包含显式动画(animateTo)和属性动画(animation)
动画类型名称特点
显式动画闭包内的变化都会触发动画执行, 可以做较复杂的动画
属性动画属性变化时触发动画执行, 设置简单

说白了,显示动画就是靠闭包事件触发,属性动画是挂在组件身上的属性变化触发

  • 显式动画 可以通过修改组件的布局方式、宽高、位置触发动画
 animateTo({ duration: 1000, curve: Curve.Ease }, () => {
            // 动画闭包中根据标志位改变控制第一个Button宽高的状态变量,使第一个Button做宽高动画
            if (this.flag) {
              this.myWidth = 100;
              this.myHeight = 50;
            } else {
              this.myWidth = 200;
              this.myHeight = 100;
            }
            this.flag = !this.flag;
          });
  • 属性动画
 Image($r('app.media.ic_hm_logo'))
    .width(160)
    .height(160)
    .alignRules({
      top: { anchor: '__container__', align: VerticalAlign.Top },
      right: { anchor: '__container__', align: this.itemAlign }
    })
    .margin({ top: this.mTop, right: 35 })
    .id('logo')
    .animation({ duration: 1000, curve: Curve.Ease }) //animation只对上面的设置生效
    .onClick(() => {
      this.mTop = 111
    })

2. 组件内转场动画(transition)

  • transition常见用法
Button()   //删除插入同一个动画
  .transition({ type: TransitionType.All, scale: { x: 0, y: 0 } })
Button()//删除插入不同动画
  .transition({ type: TransitionType.Insert, translate: { x: 200, y: -200 }, opacity: 0 })
  .transition({ type: TransitionType.Delete, rotate: { x: 0, y: 0, z: 1, angle: 360 } })

3. 弹簧曲线动画

  • 分为两类,一个springCurve,一个springMotion和responsiveSpringMotion。
  • springCurve
springCurve(velocity: number, mass: number, stiffness: number, damping: number)
//velocity:  初速度
//mass:弹簧系统的质量
//stiffness:弹簧系统的刚度
//damping:弹簧系统的阻尼
  • springMotion和responsiveSpringMotion。此动画适合跟手动画,duration设置无效。跟手过程推荐使用responsiveSpringMotion,松手时使用springMotion
springMotion(response?: number, dampingFraction?: number, overlapDuration?: number)
responsiveSpringMotion(response?: number, dampingFraction?: number, overlapDuration?: number)
//response:可选参数 弹簧自然振动周期
//dampingFraction:可选参数阻尼系数
//overlapDuration:可选参数弹性动画衔接时长
  • 注意: springCurve可以设置初速度,单一属性存在多个动画时,可以正常叠加动画效果。springMotion,由于开发者不可修改速度机制,所以在单一属性存在多个动画时,后一动画会取代前一动画。并继承前一动画的速度
  .onTouch(event => {
    if (event.type == TouchType.Move) {
      animateTo({ curve: curves.responsiveSpringMotion() }, () => {
        this.mRight = event.touches[0].screenX - 80;
      })
    } else if (event.type == TouchType.Up) {
      animateTo({curve: curves.springMotion()}, ()=>{
        this.mRight = 35;
      })
    }
  })

4. 放大缩小动画

  • sharedTransition,
  • Exchange类型的共享元素转场动画,就是前后两个页面都设置有相同id的动画,那么转场时,将会自动触发缩放动画
      .sharedTransition('sharedTransition', { duration: 1000, curve: Curve.Linear })
  • Static类型的共享元素转场动画, 只需要在一个页面设置即可,在转换页面时自动触发透明度从0到该组件原设定的的透明度的动画。位置等其他属性不变
   .sharedTransition('input', { duration: 500, curve: Curve.Linear, type: SharedTransitionEffectType.Static })

5. 页面转场动画

  • 页面转场切换时,效果触发在页面上,在pageTransition函数中设置PageTransitionEntert和PageTransitionExit动画
PageTransitionEnter({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number})
PageTransitionExit({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number})
//type:默认是RouteType.None表示对页面栈的push和pop操作均生效,
//duration: 动画时长
//curve: 动画效果
//delay: 动画延时
转场动画设置
  pageTransition() {
    PageTransitionEnter({ type: RouteType.Push, duration: 1000, })
      .slide(SlideEffect.Right)
    PageTransitionEnter({ type: RouteType.Pop, duration: 1000, })
      .slide(SlideEffect.Left)

    PageTransitionExit({type: RouteType.Push, duration: 1000})
      .slide(SlideEffect.Left)
    PageTransitionExit({type: RouteType.Pop, duration: 1000})
      .slide(SlideEffect.Right)
  }

二、 效果一览

在这里插入图片描述

三、 源码剖析

import promptAction from '@ohos.promptAction';
import picker from '@ohos.file.picker';
import thermal from '@ohos.thermal';
import router from '@ohos.router';
import curves from '@ohos.curves';

@Component
@Entry
struct LoginPage {
  @State account: string = '';
  @State password: string = '';
  dialog: CustomDialogController = new CustomDialogController({
    builder: TipDialog({
      cancel: this.onCancel,
      commit: this.onCommit,
      msg: this.account
    }),
    alignment: DialogAlignment.Center
  });

  onCancel() {
    promptAction.showToast({ message: '取消登录' })
  }

  onCommit() {
    promptAction.showToast({ message: '登录成功' })

    router.pushUrl({ url: 'pages/router/MyRouter' })
  }

  @State color: Color = 0x1f2937;
  @State itemAlign: HorizontalAlign = HorizontalAlign.Center
  allAlign: HorizontalAlign[] = [HorizontalAlign.Center, HorizontalAlign.End]
  alignIndex: number = 0;
  @State mTop: number = 106
  @State flag: boolean = true
  @State translateX: number = 0;
  @State mRight: number = 35;

  build() {
    Column() {
      RelativeContainer() {
        // Photo()

        Text('欢迎登录')
          .fontSize(25)
          .fontColor(this.color)
          .margin({ top: 111, left: 33 })
          .id('tips')
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },
            left: { anchor: '__container__', align: HorizontalAlign.Start }
          })
          .width('100%')
          .fontWeight(FontWeight.Bold)

        Image($r('app.media.ic_hm_logo'))
          .width(160)
          .height(160)
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },
            right: { anchor: '__container__', align: this.itemAlign }
          })
          .margin({ top: this.mTop, right: this.mRight })
          .id('logo')
          .animation({ duration: 1000, curve: Curve.Ease }) //animation只对上面的设置生效  属性动画

          .onTouch(event => {
            if (event.type == TouchType.Move) {
              animateTo({ curve: curves.responsiveSpringMotion() }, () => {
                this.mRight = event.touches[0].screenX - 80;
              })
            } else if (event.type == TouchType.Up) {
              animateTo({ curve: curves.springMotion() }, () => {
                this.mRight = 35;
              })
            }
          })
          .onClick(() => {
            if (this.mTop == 111) {
              this.mTop = 106
            } else {
              this.mTop = 111;
            }

            animateTo({ curve: Curve.LinearOutSlowIn, duration: 1000 }, () => {
              this.flag = !this.flag;
            })
            this.translateX = -1;
            animateTo({ curve: curves.springCurve(2000, 1, 1, 1.2), duration: 1000 }, () => {
              this.translateX = 0;
            })
          })

        if (this.flag) {
          Image($r('app.media.ic_hm_logo'))
            .width(160)
            .height(160)
            .alignRules({
              top: { anchor: '__container__', align: VerticalAlign.Top },
              right: { anchor: '__container__', align: this.itemAlign }
            })
            .margin({ top: 580, right: 35 })
            .id('bottom_logo')
            .translate({ x: this.translateX })
            .transition({ type: TransitionType.Insert, opacity: 1, scale: { x: 0, y: 0 } })
            .transition({ type: TransitionType.Delete, opacity: 0, scale: { x: 0, y: 0 } })
        }

        Image($r('app.media.ic_hm_logo'))
          .width(160)
          .height(160)
          .alignRules({
            top: { anchor: '__container__', align: VerticalAlign.Top },
            right: { anchor: '__container__', align: this.itemAlign }
          })
          .margin({ top: 600, right: 35 })
          .id('bottom_animateTo')
          .translate({ x: this.translateX })
          .sharedTransition('sharedTransition', { duration: 1000, curve: Curve.Linear })
          .onClick(() => {
            router.pushUrl({ url: 'pages/router/MyRouter' })
          })


        Text('用户名:')
          .fontSize(14)
          .fontColor(this.color)
          .alignRules({
            top: { anchor: 'tips', align: VerticalAlign.Bottom },
            left: { anchor: 'tips', align: HorizontalAlign.Start }
          })
          .margin({ top: 140, left: 33 })
          .height(20)
          .textAlign(TextAlign.Center)
          .id('account')
          .width(60)

        TextInput({ placeholder: '请输入账号' })
          .alignRules({
            top: { anchor: 'account', align: VerticalAlign.Bottom },
            left: { anchor: 'account', align: HorizontalAlign.Start }
          })
          .margin({ top: 13, left: 33, right: 33 })
          .id("etAccount")
          .height(46)
          .fontColor(this.color)
          .onChange(val => {
            this.account = val;
          })

        Text('密码:')
          .fontSize(14)
          .fontColor('#333333')
          .alignRules({
            top: { anchor: 'etAccount', align: VerticalAlign.Bottom },
            left: { anchor: 'etAccount', align: HorizontalAlign.Start }
          })
          .width(60)
          .height(20)
          .margin({ top: 15, left: 33 })
          .textAlign(TextAlign.Center)
          .id('password')
        TextInput({ placeholder: '请输入密码' })
          .alignRules({
            top: { anchor: 'password', align: VerticalAlign.Bottom },
            left: { anchor: 'password', align: HorizontalAlign.Start }
          })
          .type(InputType.Password)
          .margin({ top: 13, left: 33, right: 33 })
          .id("etPassword")
          .height(46)
          .onChange(val => {
            this.password = val;
          })

        Toggle({ type: ToggleType.Checkbox })
          .onChange((isChecked) => {
            if (isChecked) {
              promptAction.showToast({ message: "记住账号密码" })
            } else {
              promptAction.showToast({ message: "不记住密码" })
            }
          })
          .alignRules({
            top: { anchor: 'password', align: VerticalAlign.Bottom },
            left: { anchor: 'password', align: HorizontalAlign.Start }
          })
          .height(15)
          .margin({
            top: 80, left: 33
          })
          .id('isRecord')

        Text('记住密码')
          .fontColor("#999999")
          .fontSize(12)
          .height(15)
          .margin({
            top: 80,
            left: 6
          })
          .alignRules({
            top: { anchor: 'password', align: VerticalAlign.Bottom },
            left: { anchor: 'isRecord', align: HorizontalAlign.End }
          })
          .id('tvRecord')

        Button('登录', { type: ButtonType.Capsule, stateEffect: true })
          .onClick(() => {
            this.dialog.open()
            animateTo({ duration: 10000, curve: Curve.LinearOutSlowIn }, () => { //显式动画
              this.alignIndex = (this.alignIndex + 1) % this.allAlign.length;
              this.itemAlign = this.allAlign[this.alignIndex]
            })
          })
          .alignRules({
            top: {
              anchor: 'tvRecord', align: VerticalAlign.Bottom
            },
            left: { anchor: 'etAccount', align: HorizontalAlign.Start },
            right: { anchor: 'etAccount', align: HorizontalAlign.End }
          })
          .height(47)
          .margin({
            right: 23,
            top: 19,
            left: 23
          })
          .backgroundColor(0x00c250)
          .type(ButtonType.Capsule)
          .id('btCommit')
      }.width('100%')
      .height('100%')
    }
  }

  pageTransition() {
    PageTransitionEnter({ type: RouteType.Push, duration: 1000, })
      .slide(SlideEffect.Right)
    PageTransitionEnter({ type: RouteType.Pop, duration: 1000, })
      .slide(SlideEffect.Left)

    PageTransitionExit({ type: RouteType.Push, duration: 1000 })
      .slide(SlideEffect.Left)
    PageTransitionExit({ type: RouteType.Pop, duration: 1000 })
      .slide(SlideEffect.Right)
  }
}

@CustomDialog
struct TipDialog {
  dialogController: CustomDialogController;
  cancel: () => void
  commit: () => void
  msg: string;

  build() {
    Column() {
      Text('确定登录当前账号“' + this.msg + '”吗')
        .fontColor(Color.Red)
        .fontSize(44)
      Row() {

        Button('确定')
          .type(ButtonType.Capsule)
          .onClick(() => {
            this.commit()
            this.dialogController.close()
          })

        Button('取消')
          .type(ButtonType.Capsule)
          .onClick(() => {
            this.cancel()
            this.dialogController.close()
          })
      }
    }
  }
}

@Component
struct Photo {
  @State imgListData: string[] = [];

  getAllImg() { //获取照片url集

    try {
      let photoSelectOptions = new picker.PhotoSelectOptions(); //媒体库选择器设置
      photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; //图片类型
      photoSelectOptions.maxSelectNumber = 5; //最多 选取五张

      let photoPicker = new picker.PhotoViewPicker; //初始化图片选择器
      photoPicker.select(photoSelectOptions).then(photoSelectResult => { //选择结果回调
        this.imgListData = photoSelectResult.photoUris;
        console.error(`imgListData size is ${this.imgListData.length}`)
      }).catch(err => {
        console.error(`select failed code is ${err.code}, msg : ${err.message}`)
      })
    } catch (err) {
      console.error(`load photo failed ${err.code}, msg: ${err.message}`)
    }

  }

  async aboutToAppear() {
    this.getAllImg(); //获取图片url
  }

  build() {

  }
}

import http from '@ohos.net.http';
import ResponseCode from '@ohos.net.http';
import image from '@ohos.multimedia.image';
import picker from '@ohos.file.picker';
import router from '@ohos.router';

@Entry
@Component
struct MyRouter {
  private tabsController: TabsController = new TabsController();
  @State currentIndex: number = 0;

  @Builder TabBuild(title: string, targetIndex: number, SelectedImg: Resource, normalImg: Resource) {
    Column() { //自定义tab
      Image(this.currentIndex == targetIndex ? SelectedImg : normalImg)
        .size({ width: 25, height: 25 })
      Text(title)
        .fontSize(16).fontColor(this.currentIndex == targetIndex ? 0x00c250 : 0x333333)
    }
    .width('100%')
    .height(48)
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      console.error(`targetIndex is ${targetIndex}`)
      this.currentIndex = targetIndex;
      this.tabsController.changeIndex(this.currentIndex)
    })
  }

  @State image: PixelMap = undefined; //创建PixelMap状态变量

  private imgUrl: string = 'https://img1.baidu.com/it/u=3241660985,1063915045&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1194';

  loadImg() { //获取网络美女图片
    http.createHttp().request(this.imgUrl, (err, data) => {
      if (err) {
        console.error(`err is ${JSON.stringify(err)}`)
      } else {
        let code = data.responseCode;
        if (ResponseCode.ResponseCode.OK == code) {
          let res: any = data.result;
          let imageSource = image.createImageSource(res)
          let options = {
            alphaTye: 0, //透明度
            editable: false, //是否可编辑
            pixelFormat: 3, //像素格式
            scaleMode: 1, //缩略值
            size: { height: 100, wight: 100 } //创建图片大小
          }
          imageSource.createPixelMap(options).then(pixelMap => {
            this.image = pixelMap;
          })
        }
      }
    })
  }

  aboutToAppear() {

    // this.context = getContext();
    this.loadImg()
  }

  settings: RenderingContextSettings = new RenderingContextSettings(true)
  context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
  img: ImageBitmap = new ImageBitmap('../../../resources/base/media/ic_hm_logo.svg')
  scroller: Scroller = new Scroller();
  @State _50: number = vp2px(50)
  @State _100: number = vp2px(100)
  @State _85: number = vp2px(85)
  @State _15: number = vp2px(15)
  @State _: number = vp2px(50)

  build() {
    Tabs({
      barPosition: BarPosition.End,
      controller: this.tabsController
    }) { //end start  首尾位置设置   controller 绑定tabs的控制器
      TabContent() { //内容页面组件
        MyNavigation().backgroundColor(0xf7f7f7)
      }
      .tabBar(this.TabBuild('首页', 0, $r('app.media.ic_hm_home_selected'), $r('app.media.ic_hm_home_normal')))

      TabContent() {
        Image(this.image).height('100%').width('100%')
      }
      .tabBar(this.TabBuild('直播', 1, $r('app.media.ic_hm_living_selected'), $r('app.media.ic_hm_living_normal')))

      TabContent() {
        Scroll(this.scroller) {
          Column() {
            Row() {
              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Contain) //等比缩放,图片完全显示
                .margin(15)
                .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 30 } })
                .colorFilter([ //添加滤镜效果
                  1, 1, 0, 0, 0,
                  0, 1, 0, 0, 0,
                  0, 0, 1, 0, 0,
                  0, 0, 0, 1, 0
                ])
                .syncLoad(true) //同步加载图片
                .onComplete(msg => {
                  if (msg) {
                    console.error(`widthVal = ${msg.width}\n height = ${msg.height} \n componentW = ${msg.componentWidth} \n status = ${msg.loadingStatus}`)
                  }
                })
                .onError(() => {
                  console.error('err')
                })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Cover) //等比缩放, 图片显示部分
                .margin(15)
                .overlay('Cover', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Auto) //自适应显示
                .margin(15)
            }

            Row() {
              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.Fill) //填充显示,不保持等比缩放
                .renderMode(ImageRenderMode.Template) //图片渲染模式
                .margin(15)
                .overlay('fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })

              Image(this.imgUrl)
                .sourceSize({ //设置图片解码尺寸
                  width: 65, height: 40
                })
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.ScaleDown) //保持原宽高比 等比缩放或不变
                .objectRepeat(ImageRepeat.XY) //设置图片在xy轴上重复显示
                .margin(15)
                .overlay('scaleDown', { align: Alignment.Bottom, offset: { x: 0, y: 30 } })

              Image(this.imgUrl)
                .width('30%')
                .height('20%')
                .border({ width: 1 })
                .objectFit(ImageFit.None) //保持图片原尺寸
                .interpolation(ImageInterpolation.High) //图片插值,抗锯齿,使图片看着更清晰
                .margin(15)
                .overlay("none", { align: Alignment.Bottom, offset: { x: 0, y: 30 } })
            }

          }

        }.width('100%')
        .height('100%')
      }
      .tabBar(this.TabBuild('朋友圈', 2, $r('app.media.ic_hm_friend_selected'), $r("app.media.ic_hm_friend_normal")))

      TabContent() {
        Canvas(this.context)
          .width('100%')
          .height('100%')
          .backgroundColor(Color.Yellow)
          .onReady(() => {

            this.offContext.drawImage(this.image, 110, 400, 130, 130)
            let imageData = this.offContext.getImageData(150, 450, 130, 130)
            this.offContext.putImageData(imageData, 130, 130)
            let img = this.offContext.transferToImageBitmap();
            this.context.transferFromImageBitmap(img) //.截图画图

            this.context.beginPath()
            this.context.rect(110, 10, 210, 110)
            this.context.stroke()
            this.context.font = '46px'
            this.context.fillText('矩形', 120, 20) //画矩形

            this.context.beginPath()
            this.context.arc(110, 150, 50, 0, 6.28)
            this.context.stroke()
            this.context.font = '56px'
            this.context.fillText('圆形', 120, 220) //画圆形

            this.context.beginPath()
            this.context.ellipse(110, 250, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2)
            this.context.stroke() //画椭圆形

            let line = this.context.createLinearGradient(110, 500, 110, 600)
            line.addColorStop(0, '#f00')
            line.addColorStop(0.5, '#ff0')
            line.addColorStop(1, '#f0f')
            this.context.fillStyle = line
            this.context.fillRect(110, 500, 100, 100) //渐变色
            this.context.fillText('我是中华人民共和国的公民', 110, 500) //写字

            let path = new Path2D();
            path.moveTo(100, 100)
            path.lineTo(100, 150)
            path.lineTo(25, 150)
            path.lineTo(175, 150)
            path.lineTo(100, 150)
            path.lineTo(100, 200)
            path.lineTo(40, 200)
            path.lineTo(160, 200)
            path.lineTo(100, 200)
            path.closePath()
            this.context.strokeStyle = '#f00'
            this.context.lineWidth = 5
            this.context.stroke(path)

            let path2 = new Path2D();
            path2.moveTo(40, 215)
            path2.lineTo(160, 215)
            path2.lineTo(160, 335)
            path2.lineTo(40, 335)
            path2.lineTo(40, 215)
            this.context.stroke(path2) //再次画个“吉”
          })
      }
      .tabBar(this.TabBuild('画布', 3, $r('app.media.ic_hm_logo'), $r('app.media.icon')))

      TabContent() {
        Column() {

          Text('原始尺寸Circle')
          Circle({ width: 100, height: 100 }).fill(0x00c250)
          Row({ space: 10 }) {

            Column() {
              Text('shape内放大的Circle')
              Shape() {
                Rect({ width: 100, height: 100 }).fill(0xf7f7f7)
                Circle({ width: 150, height: 150 }).fill(0x00c250)
              }.viewPort({ x: 0, y: 0, width: 100, height: 100 }) //根据这个视口与宽高比进行放大shape内的组件大小
              .width(150)
              .height(150)


              Path()
                .width(100)
                .height(100)
                .commands(`M${this._50} 0 L${this._50} ${this._50} L0 ${this._50} L${this._100} ${this._50} L${this._50} ${this._50} L${this._50} ${this._100} L${this._15} ${this._100} L${this._85} ${this._100} L${this._50} ${this._100} Z`)
                .fillOpacity(0) //实心不填充颜色
                .fill(Color.Red)
                .stroke(Color.Red)
                .strokeWidth(5)

              Polyline()
                .width(100)
                .height(100)
                .stroke(Color.Red)
                .strokeWidth(5)
                .points([[10, 10], [90, 10], [90, 90], [10, 90], [10, 10]])
                .fillOpacity(0) //实心不填充颜色


            }
          }
        }
      }
      .tabBar(this.TabBuild('我的', 4, $r('app.media.ic_hm_my_selected'), $r('app.media.ic_hm_my_normal')))
    }
    .vertical(false) //tabs垂直与横向设置
    .scrollable(false) //禁止页面滑动
    .barMode((BarMode.Fixed)) //Fixed 固定    Scrollable  可以滑动,当tab多时用
    .onChange((index) => { //页面滑动监听
      console.error(`this is ${index}`)
      this.currentIndex = index;
      // this.tabsController.changeIndex(this.currentIndex)
    })
  }
}

@Component
struct MyNavigation {
  private arr: number[] = [1, 2, 3];

  build() {
    Column() {
      Navigation() {
        TextInput({ placeholder: '请输入...' })
          .width('90%')
          .height(40)
          .backgroundColor('#ffffff')
          .sharedTransition('input', { duration: 500, curve: Curve.Linear, type: SharedTransitionEffectType.Static })

        Image($r('app.media.ic_hm_logo'))
          .width(300)
          .height(300)
          .sharedTransition('sharedTransition', { duration: 500, curve: Curve.Linear })
          .onClick(() => {
            router.back()
          })

        List({ space: 12 }) {
          ForEach(this.arr, item => {
            ListItem() {
              NavRouter() {
                Text("NavRouter" + item)
                  .width('100%')
                  .height(72)
                  .backgroundColor(Color.White)
                  .borderRadius(36)
                  .fontSize(16)
                  .fontWeight(500)
                  .textAlign(TextAlign.Center)
                NavDestination() {
                  Text(`NavDestinationContent${item}`)
                }
                .title(`NavDestinationTitle${item}`)
              }
            }
          })
        }
      }
      .title('主标题')
      .mode(NavigationMode.Stack)
      .titleMode(NavigationTitleMode.Mini)
      .menus([
        { value: "", icon: './../../../resources/base/media/icon.png', action: () => {
        } },
        { value: "", icon: './../../../resources/base/media/icon.png', action: () => {
        } }
      ])
      .toolBar({ items: [
        { value: 'func', icon: './../../../resources/base/media/icon.png', action: () => {
        } },
        { value: 'func', icon: './../../../resources/base/media/icon.png', action: () => {
        } }
      ] })
    }
  }
  pageTransition() {
    PageTransitionEnter({ type: RouteType.Push, duration: 1000, })
      .slide(SlideEffect.Right)
    PageTransitionEnter({ type: RouteType.Pop, duration: 1000, })
      .slide(SlideEffect.Left)

    PageTransitionExit({type: RouteType.Push, duration: 1000})
      .slide(SlideEffect.Left)
    PageTransitionExit({type: RouteType.Pop, duration: 1000})
      .slide(SlideEffect.Right)
  }
}
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值