#HarmonyOS NEXT体验官#HarmoneyOS Next应用开发实现首次登录隐私弹窗效果 原创
背景
随着应用规范化的发展,每个应用首次打开前,都需要让用户能够清晰的看到app收集的信息,申请的权限,隐私、协议等消息供用户查看,可在首次登录弹出显示一次,后续在应用内查看,在这样的要求下,每个应用在开发的时候都需要实现隐私弹窗提醒的功能。
效果
经常开发的朋友都知道,要想实现这样的页面,我们需要用到当前框架的弹窗组件,同时想要首次登录显示弹窗,用户如果同意条款,则不再显示,不同意则直接退出应用,既然思路都没问题,那么我们在harmoneyOS里想要实现这样的业务场景需要怎么做呢?
需求分析
弹窗
首先就是弹窗的选择,可以看到弹窗的内容并不复杂,只有两个按钮以及一个说明,但是为了高自由度以及易拓展性,我们选择使用自定义弹窗来实现。
状态
用户的首次登录确认状态保存,我们选择使用用户首选项来实现
代码实现
为了实现弹窗的首次弹出,确认后状态保存效果,我们需要使用用户首选项来对状态进行持久化存储。
首先通过构造的单例对象来实现全局对象的功能,方便我们对保存的数据进行取用
(代码实现如下)
export class GlobalContext {
private constructor() {
}
private static instance: GlobalContext;
private _objects = new Map<string, Object>();
public static getContext(): GlobalContext {
if (!GlobalContext.instance) {
GlobalContext.instance = new GlobalContext();
}
return GlobalContext.instance;
}
getObject(value: string): Object | undefined {
return this._objects.get(value);
}
setObject(key: string, objectClass: Object): void {
this._objects.set(key, objectClass);
}
}
然后需要在组件中使用用户首选项preferences,先实现存取方法(代码如下)
存数据
saveIsPrivacy() {
let preferences: Promise<preferences.Preferences> = this.getDataPreferences(this);
preferences.then((result: preferences.Preferences) => {
let privacyPut = result.put(CommonConstants.PREFERENCES_KEY_PRIVACY, false);
result.flush();
privacyPut.then(() => {
Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, '已同意用户隐私协议');
}).catch((err: Error) => {
Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, '错误: ' + err);
});
}).catch((err: Error) => {
Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, '错误信息: ' + err);
});
}
取数据
private getDataPreferences(common: Object) {
return preferences.getPreferences(getContext(common), CommonConstants.PREFERENCES_FILE_NAME);
}
弹窗需要在页面构建完成之前就创建完成所以需要在生命周方法中执行查询方法来控制弹窗弹出onPageShow() {
onPageShow() {
this.context = getContext(this) as common.UIAbilityContext;
this.getDataPreferences(this).then((preferences: preferences.Preferences) => {
preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true).then((value: preferences.ValueType) => {
if (value) {
let isJumpPrivacy: boolean = (GlobalContext.getContext().getObject('isSure') as boolean) ?? false;
if (!isJumpPrivacy) {
this.dialogController.open();
}
}
});
});
}
这样就完成了对存储状态值的控制
弹窗我们选择使用自定义弹窗@CustomDialog,ui实现如下
@Preview
@CustomDialog
export default struct CustomDialogComponent {
controller: CustomDialogController = new CustomDialogController({'builder': ''});
cancel: Function = () => {};
confirm: Function = () => {};
build() {
Column() {
Text($r('app.string.dialog_text_title'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_color'))
.fontSize($r('app.float.dialog_text_privacy_size'))
.textAlign(TextAlign.Center)
.fontWeight(CommonConstants.DIALOG_TITLE_FONT_WEIGHT)
.margin({
top: $r('app.float.dialog_text_privacy_top'),
bottom: $r('app.float.dialog_text_privacy_bottom')
})
Text($r('app.string.dialog_text_privacy_content'))
.fontSize($r('app.float.dialog_common_text_size'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
Text($r('app.string.dialog_text_privacy_statement'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_statement_color'))
.fontSize($r('app.float.dialog_common_text_size'))
.onClick(() => {
this.controller.close();
GlobalContext.getContext().setObject('isSure', true);
router.pushUrl({
url: 'pages/PrivacyPage'
}).catch((error: Error) => {
Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error));
});
})
Text($r('app.string.dialog_text_declaration_prompt'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_color'))
.fontSize($r('app.float.dialog_common_text_size'))
.opacity($r('app.float.dialog_text_opacity'))
.margin({ bottom: $r('app.float.dialog_text_declaration_bottom') })
Row() {
Text($r('app.string.dialog_button_disagree'))
.fancy()
.onClick(() => {
this.controller.close();
this.cancel();
})
Blank()
.backgroundColor($r('app.color.dialog_blank_background_color'))
.width($r('app.float.dialog_blank_width'))
.height($r('app.float.dialog_blank_height'))
Text($r('app.string.dialog_button_agree'))
.fancy()
.onClick(() => {
this.controller.close();
this.confirm();
})
}
.margin({ bottom: CommonConstants.DIALOG_ROW_MARGIN_BOTTOM })
}
.width(CommonConstants.DIALOG_WIDTH_PERCENT)
.borderRadius(CommonConstants.DIALOG_BORDER_RADIUS)
.backgroundColor(Color.White)
}
}
@Extend(Text) function fancy () {
.fontColor($r("app.color.ohos_id_color_palette8"))
.fontSize($r("app.float.dialog_fancy_text_size"))
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
.layoutWeight(CommonConstants.COMMON_LAYOUT_WEIGHT)
}
这样我们在预览器中通过使用@Preview就可以查看到当前自定义弹窗ui的展示效果了,(效果如下所示)
弹窗创建完成之后在组件中对弹窗进行构造
dialogController: CustomDialogController = new CustomDialogController({
builder: CustomDialogComponent(
{
cancel: () => {
this.onCancel();
},
confirm: () => {
this.onConfirm();
}
}),
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: CommonConstants.DIALOG_CONTROLLER_DY_OFFSET },
customStyle: true,
autoCancel: false
});
只需要通过dialogController方法控制对弹窗的显示和弹出就可以了
作者你好,你使用了@CustomDialog实现弹框UI没有问题,但是在点击打开《隐私协议》的时候进行了页面跳转(router.pushUrl),在HarmonyOS中,由于系统弹窗的显示优先级高于其他组件,即使跳转到Web页面,弹窗依然会显示在最上层;这个时候就会弹框永远在最上层,而用户想看隐私协议内容无法进行浏览
参考
【HarmonyOS NEXT】 自定义弹窗页面级层级控制解决方案_鸿蒙弹窗跳转页面时显示在页面下方-CSDN博客
用Dialog方案确实有问题
参考上面的 用Stack 实现