HarmonyOS鸿蒙Next中promptAction自定义弹窗无法自定义宽度和弹窗圆角的问题如何解决

HarmonyOS鸿蒙Next中promptAction自定义弹窗无法自定义宽度和弹窗圆角的问题如何解决

【问题现象】

当需要灵活定义弹窗尺寸、圆角以及封装成工具快速调用时,使用当前弹窗方式promptAction.openCustomDialogCustomDialogController都无法很好的实现。

1. promptAction.openCustomDialog

无法灵活自定义弹窗,宽度无法自定义,弹窗的圆角无法自定义。

2. CustomDialogController

这种方式的问题是使用上很不方便,无法进行工具类封装,需要在调用的地方都实现一次。

【背景知识】

  • promptAction.openCustomDialogopenCustomDialog弹窗有限制条件:暂不支持isModal = trueshowInSubWindow = true同时使用。弹窗宽度在设备竖屏时默认为:所在窗口宽度 - 左右margin(16vp,设备为2in1时为40vp),最大默认宽度为400vp。
  • CustomDialogControllerCustomDialog自定义弹窗只能通过特定的组件触发,无法实现工具封装,适用于单点自定义弹窗,即需要在调用的地方单独实现。

【定位思路】

  1. 分析诉求:诉求是需要在多个地方触发显示一个可控制宽高尺寸和可自由设置关闭方式的窗口。
  2. 提炼关键功能:窗口、方便调用、尺寸可编辑、关闭方式可控制。
  3. 评估方案满足度:
    • promptAction.openCustomDialog:不可控制尺寸。
    • CustomDialogController:不可封装重复调用。
    • 子窗口:可封装接口随处调用,可定制化窗口尺寸、位置、圆角。

【解决方案】

  1. 将创建窗口封装成函数实现快速调用创建窗口。

代码示例如下:

// 调用页 index.ets
// 步骤1:将创建窗口封装成函数实现快速调用创建窗口。
export function createSubWindow(sub:SubWindowClass){
  // 1.获取主窗口windowStage 2.创建子窗口 3.设置子窗口属性 4.加载子窗口内容 5.显示子窗口内容
  // 获取主窗口windowStage
  windowStage_ = AppStorage.get('windowStage')
  if (windowStage_ == null) {
    console.error("Failed to create the subwindow. Cause the windowStage is null")
  }
  // 创建子窗口
  windowStage_?.createSubWindow(sub.windowName,(err:BusinessError,data) => {
    let errCode = err.code
    if (errCode) {
      console.error('Failed to create sub window. Cause:' + JSON.stringify(err))
      return
    }
    sub.subWindowClass= data
    // 设置子窗口属性:大小,位置等
    // 设置子窗口位置
    sub.subWindowClass.moveWindowTo(sub.PositionX,sub.PositionY,(err:BusinessError,data) => {
      if (err.code) {
        console.error('Failed to move the window.Cause:' + JSON.stringify(err))
        return
      }
      console.info('succeeded in moving the sub window')
    })
    // 设置子窗口大小
    sub.subWindowClass.resize(sub.windowWidth,sub.windowHeight,(err:BusinessError,data) => {
      if (err.code) {
        console.error('Failed to set the sub window size.Cause:' + JSON.stringify(err))
        return
      }
      console.info('Succeeded in setting the sub window size')
    })
    // 设置子窗口是否可触
    sub.subWindowClass.setWindowTouchable(true,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set window touch Failed' + JSON.stringify(err))
        return
      }
      console.info('set window touch succeeded')
    })
    // 设置子窗口是否全屏(能够设置的前提是未设置子窗口的位置和大小)
    sub.subWindowClass.setWindowLayoutFullScreen(true,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set window layout full screen Failed' + JSON.stringify(err))
        return
      }
      console.info('set window layout full screen succeeded')
    })
    // 加载子窗口页面
    sub.subWindowClass.setUIContent(sub.windowPath,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set sub ui content Failed. Cause:' + JSON.stringify(err))
        return
      }
      console.info('set sub window ui content succeeded')
    })
    // 显示子窗口内容
    sub.subWindowClass.showWindow((err:BusinessError,data) => {
      if (err.code) {
        console.error('show sub window Failed.Cause:' + JSON.stringify(err))
        return
      }
      console.info('show sub window succeeded')
    })
  })
}
  1. 将关闭子窗口封装成函数实现任意位置调用关闭任意窗口。

代码示例如下:

// 调用页index.ets
// 步骤2:将关闭子窗口封装成函数实现任意位置调用关闭任意窗口。
export function destroySubWindow(sub:SubWindowClass){
  sub.subWindowClass?.destroyWindow((err:BusinessError,data) => {
    if (err.code) {
      console.error('destroy sub window Failed.Cause:' + JSON.stringify(err))
      return
    }
    console.info('destroy sub window succeeded')
  })
}
  1. 将窗口尺寸、位置通过参数传入创建函数,实现窗口属性可自定义。

代码示例如下:

// 调用页index.ets
// 步骤3:将窗口尺寸、位置通过参数传入创建函数,实现窗口属性可自定义。
class SubWindowClass{
  subWindowClass:window.Window|null = null
  windowName:string =''
  windowWidth:number = 0
  windowHeight:number = 0
  PositionX:number = 0
  PositionY:number = 0
  windowPath:string =''

  constructor(subWindowClass:window.Window|null,windowName:string,windowWidth:number, windowHeight:number,PositionX:number,PositionY:number ,windowPath:string) {
    this.subWindowClass = subWindowClass
    this.windowName = windowName
    this.windowWidth = windowWidth
    this.windowHeight = windowHeight
    this.PositionX = PositionX
    this.PositionY = PositionY
    this.windowPath = windowPath
  }
}
  1. 被调用页面实现,可自定义圆角。

代码示例如下:

// 被调用页page1.ets
build() {
    Column(){
      Text(this.message)
      Button(){Text('close sub window1')}
      .onClick(()=>{
        destroySubWindow(sub1)
      })
    }
    .width('100%')
    .height('100%')
    // 步骤4:被调用页面实现,可自定义圆角。
    .borderRadius(10)
    .backgroundColor(Color.Pink)
  }

【代码实现】

1. Index.ets 调用页

代码示例如下:

// 调用页 index.ets
import {  window } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'
import { JSON } from '@kit.ArkTS'

let windowStage_:window.WindowStage|null|undefined = null

// 步骤3:将窗口尺寸、位置通过参数传入创建函数,实现窗口属性可自定义。
class SubWindowClass{
  subWindowClass:window.Window|null = null
  windowName:string =''
  windowWidth:number = 0
  windowHeight:number = 0
  PositionX:number = 0
  PositionY:number = 0
  windowPath:string =''

  constructor(subWindowClass:window.Window|null,windowName:string,windowWidth:number, windowHeight:number,PositionX:number,PositionY:number ,windowPath:string) {
    this.subWindowClass = subWindowClass
    this.windowName = windowName
    this.windowWidth = windowWidth
    this.windowHeight = windowHeight
    this.PositionX = PositionX
    this.PositionY = PositionY
    this.windowPath = windowPath
  }
}
let subWindowClass1:window.Window|null = null
let subWindowClass2:window.Window|null = null

export let sub1 = new SubWindowClass(subWindowClass1,'mysub1',500,1000,100,1500,"pages/subWindow")
let sub2 = new SubWindowClass(subWindowClass2,'mysub2',500,1000,610,1500,'pages/subWindow2')

// 步骤1:将创建窗口封装成函数实现快速调用创建窗口。
export function createSubWindow(sub:SubWindowClass){
  // 1.获取主窗口windowStage 2.创建子窗口 3.设置子窗口属性 4.加载子窗口内容 5.显示子窗口内容
  // 获取主窗口windowStage
  windowStage_ = AppStorage.get('windowStage')
  if (windowStage_ == null) {
    console.error("Failed to create the subwindow. Cause the windowStage is null")
  }
  // 创建子窗口
  windowStage_?.createSubWindow(sub.windowName,(err:BusinessError,data) => {
    let errCode = err.code
    if (errCode) {
      console.error('Failed to create sub window. Cause:' + JSON.stringify(err))
      return
    }
    sub.subWindowClass= data
    // 设置子窗口属性:大小,位置等
    // 设置子窗口位置
    sub.subWindowClass.moveWindowTo(sub.PositionX,sub.PositionY,(err:BusinessError,data) => {
      if (err.code) {
        console.error('Failed to move the window.Cause:' + JSON.stringify(err))
        return
      }
      console.info('succeeded in moving the sub window')
    })
    // 设置子窗口大小
    sub.subWindowClass.resize(sub.windowWidth,sub.windowHeight,(err:BusinessError,data) => {
      if (err.code) {
        console.error('Failed to set the sub window size.Cause:' + JSON.stringify(err))
        return
      }
      console.info('Succeeded in setting the sub window size')
    })
    // 设置子窗口是否可触
    sub.subWindowClass.setWindowTouchable(true,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set window touch Failed' + JSON.stringify(err))
        return
      }
      console.info('set window touch succeeded')
    })
    // 设置子窗口是否全屏(能够设置的前提是未设置子窗口的位置和大小)
    sub.subWindowClass.setWindowLayoutFullScreen(true,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set window layout full screen Failed' + JSON.stringify(err))
        return
      }
      console.info('set window layout full screen succeeded')
    })
    // 加载子窗口页面
    sub.subWindowClass.setUIContent(sub.windowPath,(err:BusinessError,data) => {
      if (err.code) {
        console.error('set sub ui content Failed. Cause:' + JSON.stringify(err))
        return
      }
      console.info('set sub window ui content succeeded')
    })
    // 显示子窗口内容
    sub.subWindowClass.showWindow((err:BusinessError,data) => {
      if (err.code) {
        console.error('show sub window Failed.Cause:' + JSON.stringify(err))
        return
      }
      console.info('show sub window succeeded')
    })
  })
}

// 步骤2:将关闭子窗口封装成函数实现任意位置调用关闭任意窗口。
export function destroySubWindow(sub:SubWindowClass){
  sub.subWindowClass?.destroyWindow((err:BusinessError,data) => {
    if (err.code) {
      console.error('destroy sub window Failed.Cause:' + JSON.stringify(err))
      return
    }
    console.info('destroy sub window succeeded')
  })
}

@Entry
@Component
struct Index {
  @State message:string = 'Hello World'
  build() {
    Column(){
      Text(this.message)
      Row(){
        Text('我是主页面')
      }
      .width('100%')
      .height(300)
      .backgroundColor(Color.Gray)
      .justifyContent(FlexAlign.Center)
      .alignItems(VerticalAlign.Top)
      Row(){
        Button(){Text('open sub window1')}
        .margin({bottom:20,top:20})
        .onClick(()=>{
          createSubWindow(sub1)
        })
        Button(){Text('open sub window2')}
        .margin({bottom:20,top:20})
        .onClick(()=>{
          createSubWindow(sub2)
        })
      }
      Row(){
        Button(){Text('close sub window1')}
        .onClick(()=>{
          destroySubWindow(sub1)
        })
        Button(){Text('close sub window2')}
        .onClick(()=>{
          destroySubWindow(sub2)
        })
      }
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Start)
    .justifyContent(FlexAlign.Start)
  }
}

2. 被调用页1

代码示例如下:

import {  destroySubWindow,sub1} from './Index'
@Entry
@Component
struct SubWindow {
  @State message: string = 'Hello World';

  build() {
    Column(){
      Text(this.message)
      Button(){Text('close sub window1')}
      .onClick(()=>{
        destroySubWindow(sub1)
      })
    }
    .width('100%')
    .height('100%')
    // 步骤4:被调用页面实现,可自定义圆角。
    .borderRadius(10)
    .backgroundColor(Color.Pink)
  }
}

3. 被调用页2

代码示例如下:

@Entry
@Component
struct SubWindow2 {
  @State message: string = 'mySubWindow2';

  build() {
    Column(){
      Text('i am subWindow2')
    }
    .width('100%')
    .height('100%')
     // 步骤4:被调用页面实现,可自定义圆角。
    .borderRadius(20)
    .backgroundColor(Color.Pink)
  }
}

解决问题后截图展示:

点击放大


更多关于HarmonyOS鸿蒙Next中promptAction自定义弹窗无法自定义宽度和弹窗圆角的问题如何解决的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中promptAction自定义弹窗无法自定义宽度和弹窗圆角的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中自定义弹窗的宽度和圆角

在HarmonyOS鸿蒙Next中,promptAction.openCustomDialogCustomDialogController无法灵活自定义弹窗的宽度和圆角。可以通过创建子窗口的方式来实现自定义弹窗的宽度和圆角。具体步骤如下:

  1. 封装创建子窗口的函数:通过windowStage.createSubWindow创建子窗口,并设置窗口的尺寸、位置等属性。
  2. 封装关闭子窗口的函数:通过destroyWindow关闭子窗口。
  3. 通过参数传入窗口尺寸和位置:在创建子窗口时,通过参数传入窗口的宽度、高度、位置等信息。
  4. 在被调用页面实现自定义圆角:在子窗口的页面中,通过borderRadius属性设置圆角。

示例代码如下:

// 调用页 index.ets
export function createSubWindow(sub: SubWindowClass) {
  windowStage_ = AppStorage.get('windowStage');
  if (windowStage_ == null) {
    console.error("Failed to create the subwindow. Cause the windowStage is null");
  }
  windowStage_?.createSubWindow(sub.windowName, (err: BusinessError, data) => {
    if (err.code) {
      console.error('Failed to create sub window. Cause:' + JSON.stringify(err));
      return;
    }
    sub.subWindowClass = data;
    sub.subWindowClass?.moveWindowTo(sub.PositionX, sub.PositionY, (err: BusinessError, data) => {
      if (err.code) {
        console.error('Failed to move the window.Cause:' + JSON.stringify(err));
        return;
      }
      console.info('succeeded in moving the sub window');
    });
    sub.subWindowClass?.resize(sub.windowWidth, sub.windowHeight, (err: BusinessError, data) => {
      if (err.code) {
        console.error('Failed to set the sub window size.Cause:' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in setting the sub window size');
    });
    sub.subWindowClass?.setUIContent(sub.windowPath, (err: BusinessError, data) => {
      if (err.code) {
        console.error('set sub ui content Failed. Cause:' + JSON.stringify(err));
        return;
      }
      console.info('set sub window ui content succeeded');
    });
    sub.subWindowClass?.showWindow((err: BusinessError, data) => {
      if (err.code) {
        console.error('show sub window Failed.Cause:' + JSON.stringify(err));
        return;
      }
      console.info('show sub window succeeded');
    });
  });
}

export function destroySubWindow(sub: SubWindowClass) {
  sub.subWindowClass?.destroyWindow((err: BusinessError, data) => {
    if (err.code) {
      console.error('destroy sub window Failed.Cause:' + JSON.stringify(err));
      return;
    }
    console.info('destroy sub window succeeded');
  });
}
// 被调用页 page1.ets
@Entry
@Component
struct SubWindow {
  @State message: string = 'Hello World';

  build() {
    Column() {
      Text(this.message)
      Button() { Text('close sub window1') }
        .onClick(() => {
          destroySubWindow(sub1);
        })
    }
    .width('100%')
    .height('100%')
    .borderRadius(10) // 自定义圆角
    .backgroundColor(Color.Pink)
  }
}

通过这种方式,可以实现自定义弹窗的宽度和圆角。

回到顶部