HarmonyOS NEXT列表项中的半模态转场

HarmonyOS中的半模态转场原先由Pannel组件提供该能力,但通过官方文档可知,从API Version 12 开始,该组件不再维护,推荐使用通用属性bindSheet。当然,本篇文章探讨的是列表项中的半模态转场问题。

开发环境

  • HarmonyOS NEXT Developer Beta3 SDK,基于OpenHarmony SDK Ohos_sdk_public 5.0.0.36 (API Version 12 Beta3)
  • DevEco Studio NEXT Developer Beta3

需求

一个列表项(以List+ListItem+ForEach实现),每一项包含一个按钮,点击按钮弹出模态框,展示每一项的详细信息。

解决方案

Pannel实现

@Entry
@Component
struct PanelExample {
  @State show: boolean = false

  build() {
    Column() {
      List(){
      	ForEach([1, 2, 3, 4, 5], (item: number) => {
        	ListItem() {
            	Image($r('app.media.ic_public_add_norm_filled'))
              		.width(18)
              		.onClick((event: ClickEvent) => {
                		this.show = true
              		})
        	}
      	})
      }
      Panel(this.show) { // 展示日程
        Column() {
          // 自定义内容
        }
      }
      .type(PanelType.Foldable)
      .mode(PanelMode.Half)
      .dragBar(true) // 默认开启
      .halfHeight(500) // 默认一半
      .showCloseIcon(true) // 显示关闭图标
      .onChange((width: number, height: number, mode: PanelMode) => {
        console.info(`width:${width},height:${height},mode:${mode}`)
      })
    }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
  }
}

bindSheet属性实现

@Entry
@Component
struct PanelExample {
  @State show: boolean = false
  @Builder
  sheetBuilder() {
    Column() {
      Text('测试').fontSize(18)
    }
  }
  build() {
	List({ space: 4 }) {
	  ForEach([1, 2, 3, 4, 5], (item: number) => {
	    ListItem() {
	      Image($r('app.media.ic_public_add_norm_filled'))
	        .fillColor($r('app.color.primary_color'))
	        .width(18)
	        .onClick((event: ClickEvent) => {
	          this.isShowSheet = true
	        })
	        .bindSheet($$this.show, this.sheetBuilder(), {
		      detents: ['94%'],
		      backgroundColor: Color.White,
		      blurStyle: BlurStyle.Thick,
		      showClose: false,
		    })
	    }
	  })
	}
  }
}

问题分析

Panel组件自然可以实现需求,反观bindSheet属性不出意外得出意外了。经测试,点击按钮会弹出很多模态框,再点击关闭按钮或者遮罩,只有最顶层的模态框被关闭了。代码取自官方文档示例,但为什么会产生bug呢?其实产生这个bug的矛头来自于列表项。比如列表项包含3条记录,代码中我们给每一条记录的按钮都绑定了bindSheet,但我们只用了一个状态布尔值show来控制模态框的显示和隐藏,因此点击按钮将this.show=true等同于展示所有绑定的模态框。

解决方案

  • 为了解决这个问题,我们可以定义三个变量show1show2show3分别控制列表项模态框的显示和隐藏。不过显然这不是一个明智的选择,如果列表项变多,显然无法满足我们的需求。

  • 类似于JavaScript事件委托-为父级添加监听并作用到子级,可以将bindSheet绑定到最外层的List组件中,这样就完美地实现了需求,代码如下:

    @Entry
    @Component
    struct PanelExample {
      @State show: boolean = false
      @Builder
      sheetBuilder() {
        Column() {
          Text('测试').fontSize(18)
        }
      }
      build() {
    	List({ space: 4 }) {
    	  ForEach([1, 2, 3, 4, 5], (item: number) => {
    	    ListItem() {
    	      Image($r('app.media.ic_public_add_norm_filled'))
    	        .fillColor($r('app.color.primary_color'))
    	        .width(18)
    	        .onClick((event: ClickEvent) => {
    	          this.isShowSheet = true
    	        })
    	    }
    	  })
    	}
    	.bindSheet($$this.show, this.sheetBuilder(), {
          detents: ['94%'],
          backgroundColor: Color.White,
          blurStyle: BlurStyle.Thick,
          showClose: false,
        })
      }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lewiis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值