HarmonyOS开发案例:优雅的封装一个自定义UI弹窗工具类(Dialog/PopWindow/多层嵌套弹窗)
作者寄语:
Hello,World!与时俱进,共创HarmonyOS生态,大家好,我是gelivation。
本次分享的弹窗工具类优点:可嵌套弹窗,自定义UI布局,脱离了原生组件,比较灵活,开发时自由度更高,扩展性更好。
插个题外话:ArkTS高性能之变量声明
1. 优先使用const声明常量
通过const保证地址不会发生变化
声明为const的是引用类型,引用类型内部的属性是允许改变的
对于不存在地址变化的情况下,建议使用const声明
就是讲 如果在方法中需要一个临时的对象,这个时候可以创建const的对象
2. 指定number类型
编译器会区分int和double类型,初始化number类型的变量的时候,如果预期是整数类型就初始化为0,小数类型就初始化0.0, 避免将一个number类型初始化为 nudefined 或者 null
3. 减少使用ESObject
ESObject主要用于ArkTS和TS/JS 交互的场景中作为 类型标注,在非跨语言场景中使用ESobject标注类型,会引入不必要的跨语言调用,造成额外的性能开销。
在使用ESObject时, 引入明确的 注释。
正题:封装自定义UI弹窗工具类(Dialog/PopWindow/嵌套弹窗)
先看效果(扩展: 嵌套弹窗)
点击我同意:弹出另外的弹窗
点击不同意:关闭当前弹窗
代码示例
1. 将context存储到全局
UIContext
是鸿蒙ArkUI中管理UI组件上下文的核心对象,承载动画控制、字体管理、路由操作等能力。
在Ability中的onWindowStageCreate中:
//window.getLastWindow(this.context) 用于获取当前窗口
//通过窗口对象获取 UIContext
window.getLastWindow(this.context).then((data: window.Window) => {
//通过 getUIContext() 获取上下文
let uiContext = data.getUIContext()
//将uiContext存储到全局状态管理
AppStorage.setOrCreate('uiContext', uiContext)
})
(当然可以封装一个更好的context管理类,demo我随意一点^_^)
2. 封装PopViewUtil管理类
import { ComponentContent, promptAction } from '@kit.ArkUI'
/**
* popWindow 类型
*/
export enum PopViewShowType {
OPEN,
CLOSE
}
/**
* popWindow ViewModel
*/
interface PopViewModel {
com: ComponentContent
3. 自定义view组件(隐私弹窗)
import { PopViewUtil } from "./PopWindowUtil"
@Builder
export function privacyPolicyDialog(_param: ()=> void) {
Column() {
Text('服务协议及隐私政策提示')
.fontSize('14fp')
.margin({ top: 30, bottom: 30 })
Text("欢迎使用XX!为了向您全面提供内容和社区等服务,开眼将在一定情况下收集、使用和保护您的个人信息。请充分阅读并同意《用户协议》和《隐私政策》的全面内容,并基于您的真实需求使用开眼服务。
阅读协议中如果您不同意相关协议或其中任何条款,请停止登录程序。
感谢您的信任和青睐!
")
.fontSize('14fp')
.padding({ left: (34), right: (34) })
.lineHeight(24)
Line()
.height((1))
.width('100%')
.backgroundColor('#80C7C7C7')
Row() {
Text('不同意')
.fontColor('#C7C7C7')
.fontSize('14fp')
.width('49%')
.textAlign(TextAlign.Center)
.onClick(() => {
PopViewUtil.closePopView()
})
Line()
.width(1)
.height('100%')
.backgroundColor('#80C7C7C7')
Text('我同意')
.fontSize('14fp')
.width('49%')
.textAlign(TextAlign.Center)
.onClick(() => {
_param()
// demo 把close方法放在《不同意》选项里面,这里为了展示嵌套view
// PopViewUtil.closePopView()
})
}
.justifyContent(FlexAlign.SpaceAround)
.width('100%')
.height((50))
}
.width((350))
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.backgroundColor(Color.White)
.borderRadius((5))
}
4. 使用
import { PopViewUtil } from '../PopWindowUtil';
import { privacyPolicyDialog } from '../privacyPolicyDialog';
import { promptAction } from '@kit.ArkUI';
@Entry
@ComponentV2
struct Index {
@Local message: string = 'Hello World';
//我同意 回调函数 继续弹出新弹窗
agree(): () => void {
return () => {
promptAction.showToast({ message: '同意隐私', duration: 2000 })
// 模拟多弹窗
PopViewUtil.showPopView<() => void>(wrapBuilder(privacyPolicyDialog), this.agree(),
{ alignment: DialogAlignment.Center })
}
}
build() {
RelativeContainer() {
Text(this.message)
.id('HelloWorld')
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
.onClick(() => {
// 点击后弹出
PopViewUtil.showPopView<() => void>(wrapBuilder(privacyPolicyDialog), this.agree(),
{ alignment: DialogAlignment.Center })
})
}
.height('100%')
.width('100%')
}
}
原理刨析
核心技术点
通过PopViewModel 关联 自定义view组件
在PopViewUtil中 用单例和list,方便管理已展示的弹窗列表
封装showDialog和close方法
单例方便及时更新管理list展示弹窗列表
结语
感谢大家观看,希望通过这次分享,大家能够学到一些有价值的技术,提升自己的技能水平。
我是gelivation,下期再见,拜拜~