鸿蒙HarmonyOS NEXT开发:自定义菜单栏、侧边栏交互效果的实现,滑动展示或隐藏菜单栏、侧边栏

要实现自定义菜单栏的交互效果,包括触摸滑动、平移和根据条件的显示隐藏等,滑动大于40%或速度大于500时展示或隐藏菜单栏。

您需要进行一系列的操作和设置,以下是实现这一效果的步骤:

状态定义:

首先,定义了一系列的状态变量,如 @State menuMoveX 用于记录菜单栏的平移位置,@State startX 和 @State endX 用于记录触摸事件在 x 轴的起始点和终点,@State z 用于控制主页面的放缩效果,@State flag 用于判断是否满足菜单栏全部平移出来的条件。

返回键处理:

当返回键被按下时,如果菜单栏处于完全展示状态(即 this.menuMoveX == '100%' ),则先将菜单栏平移回去,通过动画效果将 this.menuMoveX 置为 '0%' ,并设置 this.z = 0 ,然后阻止返回键的默认行为(即不退出应用),返回 true 。否则,允许返回键的默认行为,返回 false 。

触摸事件处理:

在触摸事件中,根据不同的触摸类型(如按下、移动、抬起)进行相应的处理。

在按下时,重置条件,标记菜单栏未完全平移出来。

在移动时,计算菜单栏的平移位置,并根据平移位置调整主页面的放缩效果。

在抬起时,根据平移位置判断是否满足菜单栏完全平移出来的条件,如果满足则进行相应的动画处理和状态更新,否则也进行相应的动画处理将菜单栏复位。

滑动事件处理:

通过滑动事件获取滑动速度,当不满足菜单栏完全平移出来的条件时,根据速度和起始点、终点的位置关系决定菜单栏的最终位置,并进行相应的动画处理和状态更新。

示例代码:

@Entry
@Component
struct Index {
  @State menuMoveX:string = '0' //菜单栏的平移
  @State startX:number = 0  //触摸事件x轴的起始点
  @State endX:number = 0 //触摸事件x轴的终点    判断向左或向右
  @State z:number = 0   //控制主页面的放缩效果
  @State flag:boolean = false //判断是否满足菜单栏全部平移出来的条件

  // 返回键 菜单栏展示时 不退出 先将菜单栏平移回去
  onBackPress() {
    if(this.menuMoveX=='100%'){
      animateTo({duration:300},()=>{
        this.menuMoveX='0%';this.z=0})
      return true
    }
    return false
  }

  build() {
    Stack(){
      Column({space:20}){
        Text('我是主页面')
          .fontSize(25)
      }
      .alignItems(HorizontalAlign.End)
      .translate({z:this.z})
      .animation({duration:200})
      .backgroundColor('#ffaeaeae')
      .height('100%')
      .width('100%')
      .onTouch((event:TouchEvent)=>{
        if(event.type === TouchType.Down){
          // 重置条件 刚点击时为不满足菜单栏全部平移出来的条件
          this.flag = false
          this.startX = event.touches[0].displayX
        }
        if(event.type === TouchType.Move){
            this.menuMoveX = ((event.touches[0].displayX-this.startX)/3.6).toString()+'%'
          //  防止反向滑动导致主页面的放缩异常
            this.z = parseFloat(this.menuMoveX)>0 ? parseFloat(this.menuMoveX):0
        }
        if(event.type === TouchType.Up){
          this.endX = event.touches[0].displayX
          if(parseFloat(this.menuMoveX)>40){
            // 当移动大于40%时 满足菜单栏全部平移出来的条件
            this.flag = true
            animateTo({duration:300},()=>{this.menuMoveX='100%'})
            this.z = parseFloat(this.menuMoveX)
          }else{
            animateTo({duration:300},()=>{this.menuMoveX='0%'})
            this.z = parseFloat(this.menuMoveX)
          }
        }
      })
      //  滑动事件 用于获取滑动的速度
      .gesture(
        SwipeGesture({ direction: SwipeDirection.Horizontal })
          .onAction((event: GestureEvent) => {
            //满足菜单栏全部平移出来的条件 时 无需考虑速度
            if(!this.flag){
              if (event && event.speed>=500 && this.endX>this.startX) {
                animateTo({duration:300},()=>{this.menuMoveX='100%'})
                this.z = parseFloat(this.menuMoveX)
              }else{
                animateTo({duration:300},()=>{this.menuMoveX='0%'})
                this.z = parseFloat(this.menuMoveX)
              }
            }
          })
      )

      Column(){
        Text('我是菜单栏')
      }
      .backgroundColor(Color.Pink)
      .height('100%')
      .width('100%')
      .translate({x:'-100%'})
      .offset({x:this.menuMoveX})
      .onTouch((event:TouchEvent)=>{
        if(event.type === TouchType.Down){
          // 重置条件 刚点击时为不满足菜单栏全部平移出来的条件
          this.flag = false
          this.startX = event.touches[0].displayX
        }
        if(event.type === TouchType.Move){
          //  阻止反向滑动的平移
          if(event.touches[0].displayX <= this.startX){
            this.menuMoveX = ((event.touches[0].displayX-this.startX)/3.6+100).toString()+'%'
            this.z = parseFloat(this.menuMoveX)
          }
        }
        if(event.type === TouchType.Up){
          if(parseFloat(this.menuMoveX)<60){
            // 当移动大于40%时 满足菜单栏全部平移出来的条件
            this.flag = true
            animateTo({duration:300},()=>{this.menuMoveX='0%'})
            this.z = parseFloat(this.menuMoveX)
          }else{
            animateTo({duration:300},()=>{this.menuMoveX='100%'})
            this.z = parseFloat(this.menuMoveX)
          }
        }
      })
      //  滑动事件 用于获取滑动的速度
      .gesture(
        SwipeGesture({ direction: SwipeDirection.Horizontal })
          .onAction((event: GestureEvent) => {
            //满足菜单栏全部平移出来的条件 时 无需考虑速度
            if(!this.flag){
              if (event && event.speed>=500 && this.endX<this.startX) {
                animateTo({duration:300},()=>{this.menuMoveX='0%'})
                this.z = parseFloat(this.menuMoveX)
              }else{
                animateTo({duration:300},()=>{this.menuMoveX='100%'})
                this.z = parseFloat(this.menuMoveX)
              }
            }
          })
      )
    }
    .backgroundColor(Color.White)
  }
}

注意事项:

event.touches[0].displayX貌似在预览器中无法获取到,尝试时请使用模拟器。在实际开发中,需要根据具体的需求和界面布局进行微调,以确保菜单栏的交互效果流畅自然。同时,不同的设备和屏幕尺寸可能会对触摸和滑动的响应产生影响,需要进行充分的测试和优化。另外,对于动画效果的时长和缓动函数的选择,也需要根据用户体验进行适当的调整。

本代码为基于API12,低版本API可能会出现报错。

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值