在HarmonyOS应用开发中,自定义弹窗是一个常见的需求,它涉及到模态窗口、半模态、Toast提示等多种交互形式。本文将指导您如何基于ArkUI现有能力,封装一个既好用又与UI组件解耦的弹窗组件。
场景描述
自定义弹窗通常用于以下场景:
- 公共逻辑触发:如登录提示、全屏广告、网络请求提示等。
- 侧滑手势拦截:例如隐私弹窗和退出登录确认。
- 页面切换弹窗不消失:如隐私弹窗和二级页面中的半模态弹窗。
- 自定义动画:实现弹出和关闭的自定义动画效果。
- 背景样式定制:根据需求定制透明、模态、半模态背景。
方案描述
我们将使用Navigation.Dialog
来实现弹窗效果,它支持透明页面特性,并且可以存在于路由栈中,实现页面切换时弹窗不消失的功能。
步骤一:封装路由工具类
首先,定义一个路由工具类AppRouter
,用于管理路由栈NavPathStack
。
export class AppRouter {
private static instance = new AppRouter();
private pathStack: NavPathStack = new NavPathStack();
public static getInstance(): AppRouter {
return AppRouter.instance;
}
public getPathStack(): NavPathStack {
return this.pathStack;
}
}
步骤二:封装弹窗UI组件
定义弹窗选项类AppDialogOption
和弹窗样式类AppDialogStyle
,然后创建自定义弹窗组件DefaultDialog
。
@Component
struct DefaultDialog {
private dialogOptions?: AppDialogOption;
build() {
NavDestination() {
Stack({
alignContent: this.dialogOptions?.styles?.align
}) {
Column({ backgroundColor: this.dialogOptions?.styles?.background }) {
// 模态遮罩
}
Column() {
// 弹窗内容
if (this.dialogOptions?.view) {
this.dialogOptions.view.builder(this.dialogOptions.buildParams);
}
}
}
.mode(NavDestinationMode.DIALOG);
}
.onReady((ctx: NavDestinationContext) => {
this.dialogOptions = ctx.pathInfo.param as AppDialogOption;
});
}
}
步骤三:封装弹窗控制器
提供链式调用的API,实现弹窗的打开、关闭、参数传递和动画效果。
export class AppDialog {
static indexArr: number[] = [];
private stackIndex: number = 0;
private options?: AppDialogOption;
public static buildWithOptions(options?: AppDialogOption): AppDialog {
let instance = new AppDialog();
let index = AppRouter.getInstance().getPathStack().size() - 1;
AppDialog.indexArr.push(index);
instance.stackIndex = index;
instance.options = options;
options!.instance = instance;
return instance;
}
public open(): AppDialog {
AppRouter.getInstance()
.getPathStack()
.pushPathByName(CommonConstants.DEFAULT_DIALOG, this.options, this.options!.onPop!, true);
return this;
}
public close(params?: Object): void {
if (AppRouter.getInstance().getPathStack().size() > this.stackIndex) {
AppRouter.getInstance().getPathStack().popToIndex(this.stackIndex, params);
}
}
// 其他链式调用API...
}
步骤四:页面与弹窗间传递参数
通过NavPathStack.pushPathByName
传递参数,在弹窗组件的onReady
事件中获取路由跳转参数。
步骤五:实现弹窗自定义动画
通过.transition
属性实现背景和内容的转场动画。
Stack() {
Column() {
// 模态遮罩
}
.transition(
TransitionEffect.OPACITY.animation({
duration: 300,
curve: Curve.Friction
})
)
Column() {
// 弹窗内容
}
.transition(
this.dialogOptions?.animation ?
this.dialogOptions?.animation :
TransitionEffect.scale({ x: 0, y: 0 }).animation({
duration: 300,
curve: Curve.Friction
})
)
}
步骤六:实现自定义弹窗内容
在弹窗内容的Column
容器中传入WrappedBuilder
来实现动态的自定义弹窗内容。
侧滑手势拦截
在弹窗组件的onBackPressed
事件中进行拦截。
@Component
struct DefaultDialog {
// ...
.onBackPressed((): boolean => {
if (this.dialogOptions?.onBackPressed) {
return this.dialogOptions.onBackPressed();
} else {
return false;
}
})
}
使用效果
使用AppDialog
控制器即可在非UI业务逻辑中打开弹窗。
AppDialog
.toast("登录成功")
.onBackPressed(() => true)
.autoClose(2000)
.transparent(true)
.open();
关闭弹窗时,可以使用AppDialog.closeLast()
或AppDialog.closeAll()
方法。
结语
通过封装自定义弹窗组件,我们不仅提高了代码的复用性,还使得业务逻辑与UI组件之间的耦合度降低,从而使得应用更加模块化和易于维护。希望本文能为您提供一个清晰的指南,以便在HarmonyOS NEXT应用开发中实现自定义弹窗功能。
注意:本文内容基于HarmonyOS NEXT的官方文档和实践案例,具体实现可能随SDK版本更新而变化。建议开发者持续关注官方文档,获取最新的开发指导和最佳实践。