【HarmonyOS开发】ArkUI中的自定义弹窗

弹窗是一种模态窗口,通常用来展示用户当前需要的或用户必须关注的信息或操作。在弹出框消失之前,用户无法操作其他界面内容。ArkUI 为我们提供了丰富的弹窗功能,弹窗按照功能可以分为以下两类:

  • 确认类:例如警告弹窗 AlertDialog。
  • 选择类:包括文本选择弹窗 TextPickerDialog 、日期滑动选择弹窗 DatePickerDialog、时间滑动选择弹窗 TimePickerDialog 等。

可以根据业务场景,选择不同类型的弹窗。

1、什么是自定义弹窗?

自定义弹窗的使用更加灵活,适用于更多的业务场景,在自定义弹窗中您可以自定义弹窗内容,构建更加丰富的弹窗界面。自定义弹窗的界面可以通过装饰器@CustomDialog 定义的组件来实现,然后结合 CustomDialogController 来控制自定义弹窗的显示和隐藏。

2、定义自定义弹窗

代码语言:ts
复制
@CustomDialog
struct CustomDialogExample {
  // 双向绑定传值
  @Prop title: string
  @Link inputValue: string
  // 弹窗控制器,控制打开/关闭,必须传入,且名称必须为:controller
  controller: CustomDialogController
  // 弹窗中的按钮事件
  cancel: () => void
  confirm: () => void

// 弹窗中的内容描述
build() {
Column() {
Text(this.title || "是否修改文本框内容?")
.fontSize(16)
.margin(24)
.textAlign(TextAlign.Start)
.width("100%")
TextInput({
placeholder: '文本输入框',
text: this.inputValue
})
.height(60)
.width('90%')
.onChange((value: string) => {
this.textValue = value
})
Flex({ justifyContent: FlexAlign.SpaceAround }) {
Button('取消')
.onClick(() => {
this.controller.close()
this.cancel()
}).backgroundColor(0xffffff).fontColor(Color.Black)
Button('确定')
.onClick(() => {
this.controller.close()
this.confirm()
}).backgroundColor(0xffffff).fontColor(Color.Red)
}.margin({ bottom: 10 })
}
}
}

3、使用自定义弹窗

代码语言:ts
复制
@Entry
@Component
struct Index {
@State title: string = '标题'
@State inputValue: string = '文本框父子组件数据双绑'
// 定义自定义弹窗的Controller,传入参数和回调函数
dialogController: CustomDialogController = new CustomDialogController({
builder: CustomDialogExample({
cancel: this.onCancel,
confirm: this.onAccept,
textValue: $textValue,
inputValue: $inputValue
}),
cancel: this.existApp,
autoCancel: true,
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -20 },
gridCount: 4,
customStyle: false
})

aboutToDisappear() {
this.dialogController = undefined // 将dialogController置空
}

onCancel() {
console.info('点击取消按钮', this.inputValue)
}

onAccept() {
console.info('点击确认按钮', this.inputValue)
}

build() {
Column() {
Button('打开自定义弹窗')
.width('60%')
.margin({top:320})
.zIndex(999)
.onClick(()=>{
if (this.dialogController != undefined) {
this.dialogController.open()
}
})
}
.height('100%')
.width('100%')
}

4、一个完整的示例(常用网站选择)

代码语言:ts
复制
export interface HobbyBean {
label: string;
isChecked: boolean;
}

export type DataItemType = { value: string }

@Extend(Button) function dialogButtonStyle() {
.fontSize(16)
.fontColor("#007DFF")
.layoutWeight(1)
.backgroundColor(Color.White)
.width(500)
.height(40)
}

@CustomDialog
struct CustomDialogWidget {
@State hobbyBeans: HobbyBean[] = [];

@Prop title:string;
@Prop hobbyResult: Array<DataItemType>;
@Link hobbies: string;
private controller: CustomDialogController;

setHobbiesValue(hobbyBeans: HobbyBean[]) {
let hobbiesText: string = '';
hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) =>
isCheckItem?.isChecked)
.map((checkedItem: HobbyBean) => {
return checkedItem.label;
}).join(',');
this.hobbies = hobbiesText;
}

aboutToAppear() {
// let context: Context = getContext(this);
// let manager = context.resourceManager;
// manager.getStringArrayValue($r('app.strarray.hobbies_data'), (error, hobbyResult) => {
// });
this.hobbyResult.forEach(item => {
const hobbyBean = {
label: item.value,
isChecked: this.hobbies.includes(item.value)
}
this.hobbyBeans.push(hobbyBean);
});
}
build() {
Column() {
Text(this.title || "兴趣爱好")
.fontWeight(FontWeight.Bold)
.alignSelf(ItemAlign.Start)
.margin({ left: 24, bottom: 12 })
List() {
ForEach(this.hobbyBeans, (itemHobby: HobbyBean) => {
ListItem() {
Row() {
Text(itemHobby.label)
.fontSize(16)
.fontColor("#182431")
.layoutWeight(1)
.textAlign(TextAlign.Start)
.fontWeight(500)
.margin({ left: 24 })
Toggle({ type: ToggleType.Checkbox, isOn: itemHobby.isChecked })
.margin({
right: 24
})
.onChange((isCheck) => {
itemHobby.isChecked = isCheck;
})
}
}
.height(36)
}, itemHobby => itemHobby.label)
}
.margin({
top: 6,
bottom: 8
})
.divider({
strokeWidth: 0.5,
color: "#0D182431"
})
.listDirection(Axis.Vertical)
.edgeEffect(EdgeEffect.None)
.width("100%")
// .height(248)

  Row({
    space: 20
  }) {
    Button(&#34;关闭&#34;)
      .dialogButtonStyle()
      .onClick(() =&gt; {
        this.controller.close();
      })
    Blank()
      .backgroundColor(&#34;#F2F2F2&#34;)
      .width(1)
      .opacity(1)
      .height(25)
    Button(&#34;保存&#34;)
      .dialogButtonStyle()
      .onClick(() =&gt; {
        this.setHobbiesValue(this.hobbyBeans);
        this.controller.close();
      })
  }
}
.width(&#34;93.3%&#34;)
.padding({
  top: 14,
  bottom: 16
})
.borderRadius(32)
.backgroundColor(Color.White)

}
}

@Entry
@Component
struct HomePage {
@State hobbies: string = '';
@State hobbyResult: Array<DataItemType> = [
{
"value": "FaceBook"
},
{
"value": "Google"
},
{
"value": "Instagram"
},
{
"value": "Twitter"
},
{
"value": "Linkedin"
}
]
private title: string = '常用网站'
customDialogController: CustomDialogController = new CustomDialogController({
builder: CustomDialogWidget({
hobbies: $hobbies,
hobbyResult: this.hobbyResult,
title: this.title
}),
alignment: DialogAlignment.Bottom,
customStyle: true,
offset: { dx: 0,dy: -20 }
});

build() {
Column() {
Button('打开自定义弹窗')
.width('60%')
.margin({top: 50})
.zIndex(999)
.onClick(()=>{
if (this.customDialogController != undefined) {
this.customDialogController.open()
}
})
Text(this.hobbies).fontSize(16).padding(24)
}
.width('100%')
}
}

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。