注:本人在创作过程中的疑难杂点,全以TODO Z-形式在代码中标注。设计所有页面的TODO会在结尾的注意事项中展示
一,业务逻辑
当用户打开某个软件时,弹出一个窗口询问是否同意某个隐私协议,
若同意直接就跳转首页并记住保存的选项,确保下次不会再弹出窗口;
若不同意直接退出APP。
简单如下图示:
二,实现技术
1.用户首选项:持久化存储自定义弹窗的按钮状态量数据
2.自定义弹窗:
三,代码框架
1.WelcomePage页面代码框架
...
@Entry
@Component
struct WelcomePage {
//TODO z5. 关闭APP
context=getContext(this) as common.UIAbilityContext
/*创建弹窗*/
controller:CustomDialogController=new CustomDialogController(...)
//TODO z4. 欢迎页面一加载就弹出弹窗
async aboutToAppear(){...}
/*跳转首页函数*/
jumpToIndex(){... }
/*弹窗同意函数*/
onConfirm(){...}
/*弹窗不同意函数*/
exitAPP(){...}
build(){
Column({space:10}){
//1.中央slogon
Row(){...}
...
//2.logo
Image(...)...
//3.文字描述
Row() {
Text('黑马健康支持')...
Text('IPv6')
...
Text('网络')...
}
Text('减更多指黑马健康App希望通过软件工具的形式,帮助更多用户实现身材管理')
...
Text('浙ICP备0000000号-36D')
...
}
...
}
}
2.PreferenceUtil页面代码框架
import...
class PreferenceUtil{
private pref: preferences.Preferences
async loadPreference(context){
if (!this.pref) {...}
try {...} catch (e) {...}
}
//给键值对存值
async putPreferenceValue(key: string, value: preferences.ValueType){
if (!this.pref) {...}
try {...} catch (e) {...}
}
//给默认值,取值
async getPreferenceValue(key: string, defaultValue:preferences.ValueType){
if (!this.pref) {...}
try {...} catch (e) {...}
}
const preferenceUtil = new PreferenceUtil()
export default preferenceUtil as PreferenceUtil
3.在EntryAbility页面应用启动时加载用户首选项
export default class EntryAbility extends UIAbility {
async onCreate(want, launchParam) {
// 1.加载用户首选项
PreferenceUtil.loadPreference(this.context)
// 2.初始化日期
AppStorage.SetOrCreate(CommonConstants.RECORD_DATE, DateUtil.beginTimeOfDay(new Date()))
// 3.初始化RDB工具
await DbUtil.initDB(this.context)
// 4.创建record表
DbUtil.createTable(RecordModel.getCreateTableSql())
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
4.自定义组件代码框架
import ...
//自定义弹窗
@CustomDialog
export struct UserPrivacyDialog {
contlloer:CustomDialogController
confirm:()=>void
cancel:()=>void
build() {//弹窗内容
Column(...){
//1.标题
Text(...)
//2.内容
Text(...)
//3.按钮
Button(...)
...
.onClick(()=>{...})
Button(...)
...
.onClick(()=>{...})
}
...
}
}
四,完整代码
1.UserPrivacyDialog页面--自定义组件
//TODO z1.主页面的自定义组件放view下;z2. dialog自动弹出自定义组件模版
import { CommonConstants } from '../../common/constants/CommonConstants'
//@Preview//TODO z4. 呈现组件的渲染
//自定义弹窗
@CustomDialog
export struct UserPrivacyDialog {
contlloer:CustomDialogController
//TODO z5. 只声明不实现 TODO w2. 为什么函数由用户决定
confirm:()=>void
cancel:()=>void
build() {//弹窗内容
Column({space:CommonConstants.SPACE_10}){
//1.标题
Text($r('app.string.user_privacy_title'))
.fontWeight(CommonConstants.FONT_WEIGHT_700)
.fontSize(20)
//2.内容
Text($r('app.string.user_privacy_content'))
//3.按钮
Button($r('app.string.agree_label'))
.width(150)
.backgroundColor($r('app.color.primary_color'))
.onClick(()=>{
this.confirm()
this.contlloer.close()
})
Button($r('app.string.refuse_label'))
.width(150)
.backgroundColor($r('app.color.lightest_primary_color'))
.fontColor($r('app.color.light_gray'))
.onClick(()=>{//TODO w1. 为什么()=>{}
this.cancel()
this.contlloer.close()
})
}
.width('100%')//TODO z3. 高度自适应,有多少内容就多高
.padding(10)
}
}
2.WelcomePage页面--增加自定义组件
import { UserPrivacyDialog } from '../view/welcome/UserPrivacyDialog'
import common from '@ohos.app.ability.common'
import preferences from '@ohos.data.preferences'
import preferenceUtil from '../common/utils/PreferenceUtil'
import router from '@ohos.router'
//TODO Z2.细节优化,字体格式统一化 z3.设置参数保证后续可修改
@Extend(Text) function opacitywhiteText(opacity:number,fontsize:number=10){
.fontSize(fontsize)
.fontColor(Color.White)
.opacity(opacity)//透明度
}
//TODO Z8. 设置变量key,调用用户首选项put,get都用到
const PREF_KEY='userPrivacyKey'
@Entry
@Component
struct WelcomePage {
//TODO z5. 关闭APP
context=getContext(this) as common.UIAbilityContext
/*创建弹窗*/
controller:CustomDialogController=new CustomDialogController({
builder:UserPrivacyDialog({
confirm:()=>this.onConfirm(),
cancel:()=>this.exitAPP()
})//TODO z3.需要传confirm,cancel两个函数,需要定义俩专门处理的函数
})
//TODO z4. 欢迎页面一加载就弹出弹窗
async aboutToAppear(){
//1.加载首选项
let isAgree = await preferenceUtil.getPreferenceValue(PREF_KEY,false)//TODO z6. 默认值false,状态量未改变时,继续弹窗
//2.判断是否同意
if(isAgree){
//2.1同意,跳转首页//TODO z6.router.replaceUrl方法跳转,不用push压栈因为欢迎页面出现一次即可
this.jumpToIndex()
}else{
//2.2不同意,弹窗
this.controller.open()
}
}
/*跳转首页函数*/
jumpToIndex(){
//TODO z7.跳转时需要缓冲:加载数据/看欢迎页面广告
//setTimeout定时器
setTimeout(()=>{
router.replaceUrl({
url:'pages/Index'
})
},1000)//延迟1000ms
}
/*弹窗同意函数*/
onConfirm(){
//1.保存首选项
preferenceUtil.putPreferenceValue(PREF_KEY,true)
//2.跳转到页面
this.jumpToIndex()
}
/*弹窗不同意函数*/
exitAPP(){
//退出APP
this.context.terminateSelf()
}
build(){
//space:子元素间距
Column({space:10}){
//1.中央slogon TODO z1.通过layoutWeight(1)布局权重实现第一张图片站
Row(){
Image($r('app.media.home_slogan')).width(260)
}
.layoutWeight(1)
//2.logo
Image($r('app.media.home_logo')).width(150)
//3.文字描述
Row() {
Text('黑马健康支持').opacitywhiteText(0.8,12)
Text('IPv6')
.opacitywhiteText(0.8,12)
//套边框;solid(实现);radius(边框弧度)
.border({ style: BorderStyle.Solid, width: 1, radius: 15, color: Color.White })
.padding({ left: 5, right: 5 })
Text('网络').opacitywhiteText(0.8,12)
}
Text('减更多指黑马健康App希望通过软件工具的形式,帮助更多用户实现身材管理')
.opacitywhiteText(0.6,10)
Text('浙ICP备0000000号-36D')
.opacitywhiteText(0.4,10)
.margin({bottom:35})
}
.height('100%')
.width('100%')
.backgroundColor($r('app.color.welcome_page_background'))
}
}
3.PreferenceUtil页面--用户首选项
import preferences from '@ohos.data.preferences';
import { CommonConstants } from '../constants/CommonConstants';
import Logger from './Logger';
class PreferenceUtil{
private pref: preferences.Preferences
async loadPreference(context){
try { // 加载preferences
this.pref = await preferences.getPreferences(context, CommonConstants.H_STORE)
Logger.debug(`加载Preferences[${CommonConstants.H_STORE}]成功`)
} catch (e) {
Logger.debug(`加载Preferences[${CommonConstants.H_STORE}]失败`, JSON.stringify(e))
}
}
//给键值对存值
async putPreferenceValue(key: string, value: preferences.ValueType){
if (!this.pref) {
Logger.debug(`Preferences[${CommonConstants.H_STORE}]尚未初始化!`)
return
}
try {
// 写入数据
await this.pref.put(key, value)
// 刷盘
await this.pref.flush()
Logger.debug(`保存Preferences[${key} = ${value}]成功`)
} catch (e) {
Logger.debug(`保存Preferences[${key} = ${value}]失败`, JSON.stringify(e))
}
}
//给默认值,取值
async getPreferenceValue(key: string, defaultValue: preferences.ValueType){
if (!this.pref) {
Logger.debug(`Preferences[${CommonConstants.H_STORE}]尚未初始化!`)
return
}
try {
// 读数据
let value = await this.pref.get(key, defaultValue)
Logger.debug(`读取Preferences[${key} = ${value}]成功`)
return value
} catch (e) {
Logger.debug(`读取Preferences[${key}]失败`, JSON.stringify(e))
}
}
}
const preferenceUtil = new PreferenceUtil()
export default preferenceUtil as PreferenceUtil
4.EntryAbility页面--加载用户首选项
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import { CommonConstants } from '../common/constants/CommonConstants';
import DateUtil from '../common/utils/DateUtil';
import DbUtil from '../common/utils/DbUtil';
import PreferenceUtil from '../common/utils/PreferenceUtil';
import RecordModel from '../model/RecordModel';
export default class EntryAbility extends UIAbility {
async onCreate(want, launchParam) {
//TODO z1.应用启动时加载用户首选项
// 1.加载用户首选项
PreferenceUtil.loadPreference(this.context)
// 2.初始化日期
AppStorage.SetOrCreate(CommonConstants.RECORD_DATE, DateUtil.beginTimeOfDay(new Date()))
// 3.初始化RDB工具
await DbUtil.initDB(this.context)
// 4.创建record表
DbUtil.createTable(RecordModel.getCreateTableSql())
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
//TODO z1. 默认加载页面是WelcomePage
windowStage.loadContent('pages/WelcomePage', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}