鸿蒙Harmony Next封装一个自定义底部半屏弹窗

261 阅读1分钟

鸿蒙系统自带的弹窗CustomDialog比较丑,两边会有间隙,并且底部有圆角

  • 不自定义的效果

image.png

  • 产品期望的效果

Screenshot_20250423140137587.jpeg

1.写一个自定义的Dialog

@CustomDialog
export struct RelativeStockDialog {
  controller: CustomDialogController;
  title: string | Resource = '';       // 标题
  maxScrollHeight: Length = '70%';     // 最大可滚动区域高度
  wrapBuilder?: WrappedBuilder<[string,string,string]>;    // 自定义视图创建方式
  @Link showFlag: Visibility;          // 视图是否显示,用于底部弹窗出现与消失时的动效处理
  @StorageLink('bottomHeight') bottomHeight: number = 0; // 底部导航栏高度
  @Link chainTypeCode?:string
  @Link  futVarietyCode?:string
  @Link  spotCode?:string

  build() {
    Column() {
      RelativeContainer() {
        ...

        Image($r('app.media.zs_icon_dialog_close'))
          .width(40)
          .height(40)
          .padding(10)
          .alignRules({
            right: { anchor: '__container__', align: HorizontalAlign.End },
            center: { anchor: '__container__', align: VerticalAlign.Center }
          })
          .offset({
            x: -20
          })
          .onClick(() => {
            this.closeDialog();
          })
          .id('close_image')
      }.width('100%')
      .height(52)

      Scroll() {
        Column() {
          if (this.wrapBuilder) {
            this.wrapBuilder.builder(this.chainTypeCode,this.futVarietyCode,this.spotCode)
          }
        }.width('100%')
        .padding({ bottom: this.bottomHeight + 'px' })
      }.width('100%')
      .constraintSize({maxHeight: this.maxScrollHeight
      })
      .id('scroll')
    }.width('100%')
    .backgroundColor($r('app.color.zs_palette_ffffff'))
    .borderRadius({
      topLeft: 20,
      topRight: 20
    })
    .height('45%')
    // .visibility(this.showFlag)
    .transition(TransitionEffect.OPACITY.animation({ duration: ANIMATION_DURATION })  // 弹窗出现与消失的动效
      .combine(TransitionEffect.translate({ y: Y_TRANSLATE_DISTANCE })),
      (transitionIn: boolean) => {
        if (!transitionIn) {
          this.controller.close();
        }
      }
    )
  }

  /**
   * 关闭弹窗
   */
  private closeDialog() {
    this.showFlag = Visibility.Hidden;
    this.controller.close();
  }
}

2.看看如何调用

mReStockController: CustomDialogController = new CustomDialogController({
  builder: ZsRelativeStockDialog({
    title: "相关股票",
    maxScrollHeight: 600,
    wrapBuilder: wrapBuilder(buildRelativeDialogContent),
    ...
    futVarietyCode:this.futVarietyCode,
    spotCode:this.spotCode
  }),
  alignment: DialogAlignment.Bottom,
  width: '100%',
  customStyle: true,
  autoCancel: true,
  onWillDismiss: () => {
    this.relativeDialogShowFlag = Visibility.Hidden;
  }
});

3.为了好维护,把显示弹窗内容的组件抽取处理

export struct RelativeContent{
  @State abstr?:string =""
  @State   bcCode?:string=""
  @State   spCode?:string=""
  build() {
    Column() {
      Rect().fill('#F5F6F7FF').height(10).width('100%')
      Column() {
        Row() {
          Text('股票').fontColor($r('app.color.zs_palette_73000000')).fontSize(14)
          Text('最新').fontColor($r('app.color.zs_palette_73000000')).fontSize(14)
          Text('涨跌幅').fontColor($r('app.color.zs_palette_73000000')).fontSize(14)

        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        Row() {
          Text(this.chainTypeCode).fontColor($r('app.color.zs_palette_73000000')).fontSize(14)
          ...
          Text(this.spotCode).fontColor($r('app.color.zs_palette_73000000')).fontSize(14)

        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)

      }

      .padding({
        top: 10,
        bottom: 15,
        left: 15,
        right: 15
      })
    }
    .width('100%')
  }
}

参考链接:

1.developer.huawei.com/consumer/cn…