
#我的鸿蒙开发手记#鸿蒙打卡场景实现 原创 精华
一、介绍与准备
1.整体介绍
本练习主要围绕基于华为手机直板机及 HarmonyOS 5.0.0 以上版本、DevEco Studio 5.0.0 以上版本等环境进行打卡场景开发展开。
先是介绍了应用的整体构建布局设计,涵盖登录模块与打卡模块,其中登录模块会在进入应用时检测账号登录状态,未登录则进入登录界面,已登录则直接进入打卡页面。接着详细阐述了打卡 UI 布局的开发,包括创建 constants 常量文件来定义底部导航栏配置数组,以及主入口页面的构建,该页面包含主打卡页面、打卡记录页面和快捷设置页面等。
最后深入讲解了打卡功能的实现,如在根目录 OfficeAttendance 下创建 scenes 场景文件目录,实现打卡记录获取、打卡操作、动画效果、快捷设置等功能,涵盖了从页面构建到功能实现的各个环节,基本呈现了一个完整的打卡场景开发案例。
2.基础准备
(1)设备类型:华为手机(直板机)
(2)HarmonyOS版本:HarmonyOS 5.0.0 Release及以上
(3)DevEco Studio版本:DevEco Studio 5.0.0 Release及以上
(4)HarmonyOS SDK版本:HarmonyOS 5.0.0 Release SDK及以上
二、应用整体构建布局设计
1.模块设计
(1)登录模块:Login.ets
(2)打卡模块:CheckInView.ets
2.登录UI布局开发与功能实现
进入应用时,检测是否有账号已登陆,未登录进入进入登录界面,若以登录则直接进入应用打卡页。
Login.ets关键代码如下:
// 导入登录页面组件、路由管理及ArkUI框架模块
import { LoginView } from '@ohos_agcit/office_attendance_account'
import { MainEntryVM, RouterMap, RouterModule } from '@ohos_agcit/office_attendance_common_lib';
import { router, window } from '@kit.ArkUI';
@Entry // 标记为入口组件
@ComponentV2 // 声明为ArkUI V2版本组件
struct Login { // 定义登录页面组件
// 使用单例模式获取路由管理对象
vm: MainEntryVM = MainEntryVM.instance;
// --------------------------
// 生命周期方法:页面显示时触发
// --------------------------
onPageShow(): void {
// 获取当前窗口实例并开启隐私模式(隐藏敏感内容)
window.getLastWindow(getContext(this)).then((windowStage: window.Window) => {
windowStage.setWindowPrivacyMode(true);
});
}
// --------------------------
// 生命周期方法:页面隐藏时触发
// --------------------------
onPageHide(): void {
// 获取当前窗口实例并关闭隐私模式
window.getLastWindow(getContext(this)).then((windowStage: window.Window) => {
windowStage.setWindowPrivacyMode(false);
});
}
-------------------------
build() {
// 创建导航容器(堆栈模式)
Navigation(this.vm.navStack) {
Row() { // 行布局容器
// 加载登录组件,设置登录成功回调
LoginView({
'callback': () => {
// 登录成功后跳转至主页面(替换当前路由)
router.replaceUrl({url: 'pages/MainEntry'})
}
});
}
}
// 导航栏配置:隐藏标题栏/工具栏/返回按钮
.hideTitleBar(true)
.hideToolBar(true)
.hideBackButton(true)
// 设置导航模式为堆栈(先进后出)
.mode(NavigationMode.Stack);
}
}
3.打卡UI布局开发
(1)在ets下创建contants常量文件。
(2)Constants.ets代码实现:
// 导入底部导航栏Tab项类型定义
import { TabListItem } from '@ohos_agcit/office_attendance_agency'
// 定义底部导航栏配置数组
export const TAB_LIST: TabListItem[] = [
// 第一个Tab:考勤打卡模块
{
label: $r('app.string.attendance'), // 文字标签
icon: $r('app.media.attendance'), // 默认状态图标(未选中时显示)
iconChecked: $r('app.media.attendance_checked'), // 选中状态图标
titleBackgroundColor: Color.White // 标题栏背景色(白色)
},
// 第二个Tab:待办任务模块
{
label: $r('app.string.agency_task'),
icon: $r('app.media.agency_task'),
iconChecked: $r('app.media.agency_task_checked'),
titleBackgroundColor: Color.White
},
// 第三个Tab:日程管理模块
{
label: $r('app.string.schedule'),
icon: $r('app.media.schedule'),
iconChecked: $r('app.media.schedule_checked'),
titleBackgroundColor: Color.White
},
// 第四个Tab:个人中心模块
{
label: $r('app.string.mine'),
icon: $r('app.media.mine_unchecked'),
iconChecked: $r('app.media.mine_checked'),
titleBackgroundColor: $r('app.color.title_background_color') // 特殊背景色
}
];
(3)products产品层下的pages>MainEntry.ets关键代码实现:
// 导入模块:底部导航配置、各功能模块视图、类型定义等
import { TAB_LIST } from '../constants/Constants';
import { AgencyTaskView } from '@ohos_agcit/office_attendance_agency';
import { ScheduleView } from '@ohos_agcit/office_attendance_schedule';
import { TabListItem } from '@ohos_agcit/office_attendance_agency';
import { CheckInView } from '@ohos_agcit/office_attendance_checkin';
import { CommonConstants, MainEntryVM } from '@ohos_agcit/office_attendance_common_lib';
import { MineView } from '@ohos_agcit/office_attendance_account';
import { router } from '@kit.ArkUI';
// --------------------------
// 主入口页面构建器(供外部调用)
// --------------------------
@Builder
export function mainEntryBuilder() {
MainEntry();
}
@Entry // 标记为应用入口组件
@ComponentV2 // 声明为ArkUI V2版本组件
struct MainEntry {
// 路由管理单例
vm: MainEntryVM = MainEntryVM.instance;
// 页面状态控制
@Provider() isPageShow: boolean = false; // 页面是否显示
@Provider() currentTabIndex: number = this.vm.curIndex; // 当前选中Tab索引
onPageShow(): void {
this.isPageShow = true; // 页面显示时更新状态
}
onPageHide(): void {
this.isPageShow = false; // 页面隐藏时更新状态
}
build() {
Navigation(this.vm.navStack) { // 导航容器(管理页面堆栈)
// 底部导航栏配置
Tabs({
barPosition: BarPosition.End, // 导航栏位置(底部)
index: this.vm.curIndex // 当前选中索引
}) {
// Tab1: 考勤打卡模块
TabContent() {
CheckInView(); // 加载打卡组件
}
.tabBar(this.tabBarBuilder(TAB_LIST[0], 0)); // 绑定导航栏样式
// Tab2: 待办任务模块
TabContent() {
//AgencyTaskView(); // 加载待办组件
}
.tabBar(this.tabBarBuilder(TAB_LIST[1], 1));
// Tab3: 日程管理模块
TabContent() {
//ScheduleView(); // 加载日程组件
}
.tabBar(this.tabBarBuilder(TAB_LIST[2], 2));
// Tab4: 个人中心模块
TabContent() {
//MineView({ // 加载个人中心组件
// callback: () => { // 退出登录回调
// router.replaceUrl({ url: 'pages/Login' }) // 跳转登录页
// }
});
}
.tabBar(this.tabBarBuilder(TAB_LIST[3], 3));
}
// 导航栏样式配置
.scrollable(false) // 禁止滑动切换
.barHeight(80) // 导航栏高度
.height(CommonConstants.FULL_HEIGHT) // 全屏高度
.animationDuration(0) // 禁用切换动画
.barMode(BarMode.Fixed) // 固定模式(不随内容滚动)
.onChange((index: number) => { // Tab切换事件
this.vm.curIndex = index; // 更新路由管理状态
this.currentTabIndex = index; // 更新当前索引
});
}
// 导航栏标题配置
.title({
builder: this.titleBuilder(TAB_LIST[this.vm.curIndex]), // 动态标题
height: 92 // 标题栏高度
})
.mode(NavigationMode.Stack) // 堆栈导航模式
}
@Builder
titleBuilder(title: TabListItem) {
Row() {
Text(title.label) // 显示当前模块名称
.fontWeight(FontWeight.Bold) // 加粗
.fontColor('rgba(0,0,0,0.90)') // 字体颜色
.fontSize($r('app.float.navigation_title_font_size')) // 字体大小(资源引用)
.margin({ left: 16, top: 36 }) // 边距
.height(56) // 高度
}
.justifyContent(FlexAlign.Start) // 左对齐
.backgroundColor(title.titleBackgroundColor) // 背景色(动态配置)
.width('100%') // 全宽
.height('100%') // 全高
.alignItems(VerticalAlign.Bottom) // 垂直底部对齐
}
// --------------------------
// 底部导航栏Item构建器
// --------------------------
@Builder
tabBarBuilder(item: TabListItem, index: number) {
Column() { // 垂直布局
// 动态显示选中/未选中图标
Image(this.vm.curIndex === index ? item.iconChecked : item.icon)
.width($r('app.float.navigation_image_size')) // 图标宽度(资源引用)
.height($r('app.float.navigation_image_size')) // 图标高度
.margin({ top: $r('app.string.margin_xs') }); // 上边距
// Tab文字标签
Text(item.label)
.fontColor(this.vm.curIndex === index ?
$r('app.color.icon_color_highlight') : // 选中高亮色
$r('app.color.icon_color_level2')) // 未选中默认色
.fontSize($r('app.float.navigation_navi_size')) // 字体大小
.height(14) // 固定高度
.margin({
top: $r('app.string.margin_xs'),
bottom: $r('app.string.margin_xs')
});
}
.height(80) // 固定高度
.width('100%') // 全宽
.justifyContent(FlexAlign.Start); // 顶部对齐
}
}
三、打卡功能模块与实现流程
1.打卡模块UI结构设计
打卡由以下核心组件构成:
·主打卡页面:显示当前定位、打卡按钮、快捷设置入口;
·打卡记录页面:以列表形式展示历史打卡数据;
·快捷设置页面:配置常用打卡地点与时间。
2.功能实现步骤
(1)CheckInView.ets文件创建与实现代码:
①在根目录OfficeAttendance下创建scenes场景文件目录
②在scenes目录下创建checkin模块(HSP动态共享)
③CheckInView.ets代码实现:
// 导入ArkUI动画曲线、路由管理模块、网络请求代理和类型定义
import { curves } from '@kit.ArkUI';
import { DialogMap, RouterModule } from '@ohos_agcit/office_attendance_common_lib';
import { RequestProxy } from '../api/RequestProxy';
import { CheckInHistoryDetailDataItem } from '../types/Types';
import { CheckInComponent } from './components/CheckInComponent';
// --------------------------
// 考勤打卡主页面组件
// --------------------------
@ComponentV2
export struct CheckInView {
// 本地状态管理
@Local checkinFirstTime: string = ''; // 当天首次打卡时间
@Local checkinLastTime: string = ''; // 当天最后打卡时间
@Local imageOpacity: number = 1; // 箭头图标透明度(用于呼吸动画)
@Local timerId: number = 0; // 定时器ID
// --------------------------
// 组件即将显示时触发
// --------------------------
aboutToAppear() {
this.refreshCheckDetail(); // 初始化打卡数据
// 启动箭头呼吸动画定时器(800ms间隔切换透明度)
this.timerId = setInterval(() => {
this.imageOpacity = this.imageOpacity === 1 ? 0 : 1;
}, 800);
}
// --------------------------
// 获取当天打卡记录详情
// --------------------------
private refreshCheckDetail() {
RequestProxy.getTodayCheckInDetail().then((value: CheckInHistoryDetailDataItem[]) => {
if (value.length > 0) {
this.checkinFirstTime = value[0].time; // 取第一条作为首次打卡
this.checkinLastTime = value[value.length - 1].time; // 取最后一条作为末次打卡
}
});
}
// --------------------------
// 组件即将消失时触发
// --------------------------
aboutToDisappear(): void {
clearInterval(this.timerId); // 清除动画定时器防止内存泄漏
}
// --------------------------
// 页面构建
// --------------------------
build() {
// 纵向弹性布局(内容区与底部信息栏上下分布)
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) {
// 1. 主打卡组件(占满剩余空间)
CheckInComponent({
onCheckIn: () => { // 打卡成功回调
this.refreshCheckDetail() // 刷新打卡记录
}
}).flexGrow(1)
// 2. 底部信息栏
Column() {
// 2.1 动态箭头指示器
Image($r('app.media.double_arrow_up')) // 双箭头图标
.height(16)
.width(80)
.opacity(this.imageOpacity) // 动态透明度
.animation({
duration: 800,
curve: curves.springMotion() // 弹性动画曲线
})
.margin({ top: 4 })
.onClick(() => { // 点击跳转打卡历史弹窗
RouterModule.openDialog(DialogMap.CHECK_IN_HISTORY)
})
// 2.2 打卡时间展示区
Row() {
// 首次打卡时间
Column() {
Text($r('app.string.checkin_first_time')) // 国际化文案
.fontSize(14)
.fontColor($r('app.string.white_60')) // 60%透明度白色
.height(20)
Text(this.checkinFirstTime) // 动态时间数据
.fontSize(18)
.fontColor(Color.White)
.height(24)
}.alignItems(HorizontalAlign.Start)
// 末次打卡时间
Column() {
Text($r('app.string.checkin_last_time'))
.fontSize(14)
.fontColor($r('app.string.white_60'))
.height(20)
Text(this.checkinLastTime)
.fontSize(18)
.fontColor(Color.White)
.height(24)
}.alignItems(HorizontalAlign.Start)
}
.margin({ top: 24 })
.justifyContent(FlexAlign.SpaceAround) // 两端对齐
.width('100%')
}
.flexShrink(0) // 禁止压缩高度
.height(113) // 固定高度
.width('100%')
.borderRadius({ topLeft: 36, topRight: 36 }) // 顶部圆角
.backgroundColor($r('app.color.checkin_background')) // 背景色
.align(Alignment.Top)
// 添加上滑手势(打开历史记录)
.gesture(
PanGesture({ direction: PanDirection.Up })
.onActionEnd(() => {
RouterModule.openDialog(DialogMap.CHECK_IN_HISTORY)
})
}.height('100%')
}
}
(2)步骤一:打卡记录页面
描述:签到组件,以列表形式展示历史打卡数据
CheckInComponent.ets代码实现:
// 导入基础模块:动画、路由、工具类等
import {
DialogMap,
FormatUtil,
LocationUtil,
MainEntryVM,
RouterModule,
TabIndex,
VibratorUtil,
WindowUtil
} from '@ohos_agcit/office_attendance_common_lib'
import { CheckInStatus } from '@ohos_agcit/office_attendance_common_lib/src/main/ets/constants/CheckInEnums';
import { Animator as animator, AnimatorResult } from '@kit.ArkUI';
import { RequestProxy } from '../../api/RequestProxy';
import { CheckInChannelUtil } from '../util/CheckInChannelUtil';
import { ServiceCardNotificationUtil } from '../util/ServiceCardNotificationUtil';
// --------------------------
// 考勤打卡核心组件
// --------------------------
@ComponentV2
export struct CheckInComponent {
// 组件状态管理
@Local checkInComponentHeight: number | string = '100%' // 滚动区域高度
private circleAnimator: AnimatorResult | undefined = this.create() // 打卡按钮动画控制器
// --------------------------
// 创建打卡按钮动画
// --------------------------
create(): AnimatorResult {
const circleAnimator = animator.create({
duration: 1000, // 动画时长1秒
easing: 'ease-in-out', // 缓动效果
delay: 0, // 无延迟
fill: 'backwards', // 动画结束后保持结束状态
direction: 'alternate', // 往返播放
iterations: -1, // 无限循环
begin: 1, // 初始缩放值
end: 1.05 // 结束缩放值
})
// 动画帧回调
circleAnimator.onFrame = (value: number) => {
this.scaleX = value;
this.scaleY = value;
}
return circleAnimator;
}
// 参数与状态定义
@Param onCheckIn: () => void = () => {}; // 打卡成功回调
@Local checkInStatus: CheckInStatus = CheckInStatus.NOT_STARTED; // 打卡状态
@Local max: number = 170; // 外圈最大尺寸
@Local min: number = 160; // 内圈最小尺寸
@Local scaleX: number = 1; // X轴缩放
@Local scaleY: number = 1; // Y轴缩放
@Local displayAddition: boolean = false; // 是否显示附加信息
@Local timerId: number = 0; // 定时器ID
@Local location: string | undefined = undefined; // 打卡位置
@Local time: string = FormatUtil.formatTime(new Date()) // 当前时间
@Consumer() isPageShow: boolean = false; // 页面显示状态
@Consumer() currentTabIndex: number = MainEntryVM.instance.curIndex; // 当前Tab索引
// --------------------------
// 监听页面显示状态变化
// --------------------------
@Monitor('isPageShow')
tryCheckInAutomatically() {
if (this.isPageShow) {
// 服务卡片快捷打卡
if (CheckInChannelUtil.fromServiceCard()) {
this.checkin();
CheckInChannelUtil.reset();
} else {
// 检查是否开启快捷打卡
RequestProxy.isQuickCheckIn().then((value: boolean) => {
if (value) this.checkin();
})
}
}
}
// --------------------------
// 监听Tab切换事件
// --------------------------
@Monitor('currentTabIndex')
tryWhenTabChanged() {
if (this.currentTabIndex === TabIndex.CHECKIN) {
RequestProxy.isQuickCheckIn().then((value: boolean) => {
if (value) this.checkin();
})
}
}
// --------------------------
// 组件生命周期
// --------------------------
aboutToAppear() {
this.calculateScrollAreaHeight(); // 计算滚动区域高度
// 每秒更新时间显示
this.timerId = setInterval(() => {
this.time = FormatUtil.formatTime(new Date());
}, 1000);
}
aboutToDisappear(): void {
clearInterval(this.timerId); // 清除定时器
}
// --------------------------
// 组件构建
// --------------------------
build() {
Scroll() {
Stack() {
// 主内容区
Column() {
// 打卡按钮区域
Stack() {
// 背景圆圈动画
Shape() {
this.circleBuilder(this.max, 0.1) // 外圈(半透明)
this.circleBuilder(this.min, 1.0) // 内圈(实心)
}.align(Alignment.Center).width(180).height(180)
// 不同状态下的UI展示
this.checkInBuilder($r('app.media.click'), $r('app.string.checkin_tip'), CheckInStatus.NOT_STARTED)
this.checkInBuilder($r('app.media.ticking'), $r('app.string.checkin_is_finished'), CheckInStatus.FINISHED)
this.checkInStatusTipBuilder($r('app.string.checkin_is_on_going'), CheckInStatus.ON_GOING)
this.checkInStatusTipBuilder($r('app.string.checkin_is_failed'), CheckInStatus.FAILED)
}
.onClick(async () => { this.checkin(); })
.margin({ top: 76 })
// 附加信息(位置/时间)
this.additionBuilder()
}
.alignItems(HorizontalAlign.Center)
.width('100%')
// 设置按钮
Stack() {
Circle().shadow({ radius: vp2px(8) }) // 白色圆形背景
Image($r('app.media.settings')).height(24).width(24) // 设置图标
}
.onClick(() => {
RouterModule.openDialog(DialogMap.CHECK_IN_SETTINGS) // 打开设置弹窗
})
.alignContent(Alignment.BottomEnd) // 右下角定位
}
}
.onAreaChange(() => { this.calculateScrollAreaHeight() }) // 区域变化时重新计算高度
}
// --------------------------
// 构建方法
// --------------------------
// 圆圈构建器
@Builder
circleBuilder(size: number, opacity: number) {
Circle()
.width(size).height(size)
.scale({ x: this.scaleX, y: this.scaleY }) // 动态缩放
.fillOpacity(opacity)
.fill($r('app.color.checkin_background')) // 使用主题色
}
// 打卡按钮构建器
@Builder
checkInBuilder(image: Resource, text: Resource, checkInStatus: CheckInStatus) {
Column() {
Image(image).opacity(this.checkInStatus === checkInStatus ? 1 : 0) // 状态匹配时显示
Text(text).fontColor(Color.White).opacity(this.checkInStatus === checkInStatus ? 1 : 0)
}.height(160)
}
// 打卡状态提示构建器
@Builder
checkInStatusTipBuilder(text: Resource, checkInStatus: CheckInStatus) {
Text(text)
.fontColor(Color.White)
.opacity(this.checkInStatus === checkInStatus ? 1 : 0) // 状态匹配时显示
.scale({ x: this.scaleX, y: this.scaleY }) // 同步缩放动画
}
// 附加信息构建器
@Builder
additionBuilder() {
if (this.displayAddition) {
Column() {
Text(this.location) // 位置信息
Divider().color($r('app.color.checkin_background')) // 分隔线
Text(this.time).fontSize(26) // 时间信息
}
}
}
// --------------------------
// 业务逻辑
// --------------------------
// 添加打卡记录
addCheckInDetail(address: string) {
RequestProxy.addCheckInDetail({
'day': FormatUtil.formatDate(new Date()),
'location': address,
'time': this.time
})
}
// 执行打卡操作
checkin() {
if (this.checkInStatus !== CheckInStatus.NOT_STARTED) return;
this.circleAnimator?.play(); // 启动动画
this.checkInStatus = CheckInStatus.ON_GOING;
VibratorUtil.notification(500, 0); // 震动反馈
// 超时处理(8秒未获取位置则失败)
const timeoutId = setTimeout(() => {
this.checkInStatus = CheckInStatus.FAILED;
this.finishAnimator();
this.resetCheckInStatusLater();
}, 8000);
// 获取定位
LocationUtil.getLocationName().then((address: string | undefined) => {
clearInterval(timeoutId);
if (this.checkInStatus === CheckInStatus.FAILED) return;
if (address) {
this.location = address;
this.checkInStatus = CheckInStatus.FINISHED;
this.displayAddition = true;
this.addCheckInDetail(address); // 保存记录
this.onCheckIn(); // 触发回调
} else {
this.checkInStatus = CheckInStatus.FAILED;
}
this.resetCheckInStatusLater();
ServiceCardNotificationUtil.notify(this.checkInStatus); // 通知服务卡片
});
}
// 辅助方法
private finishAnimator() {
this.circleAnimator?.finish();
this.scaleX = this.scaleY = 1; // 重置缩放
}
private resetCheckInStatusLater() {
setTimeout(() => {
this.checkInStatus = CheckInStatus.NOT_STARTED; // 1.5秒后重置状态
ServiceCardNotificationUtil.notify(this.checkInStatus);
}, 1500);
}
// 计算滚动区域高度
private calculateScrollAreaHeight() {
const windowHeight = WindowUtil.getInstance()?.getAppStorageData().windowHeightVp as number;
const minHeight = 435; // 设计稿最小高度
this.checkInComponentHeight = (windowHeight - 56 - 36 - 113 - 80 > minHeight) ? '100%' : minHeight;
}
}
(3)步骤二:快捷设置页面
描述:配置常用打卡地点与时间,进入打卡界面时自动打卡一次
CheckInSettings.ets代码实现:
// 导入路由管理、基础组件和网络请求模块
import { RouterModule } from '@ohos_agcit/office_attendance_common_lib';
import { BlankBackground } from '@ohos_agcit/office_attendance_component_lib';
import { BaseResponse } from '@ohos_agcit/office_attendance_network';
import { RequestProxy } from '../../api/RequestProxy';
// --------------------------
// 快捷打卡设置弹窗构建器(供外部调用)
// --------------------------
@Builder
export function checkinSettingBuilder() {
CheckInSettings();
}
// --------------------------
// 快捷打卡设置组件
// --------------------------
@ComponentV2
export struct CheckInSettings {
@Local isQuickCheckIn: boolean = false; // 是否开启快捷打卡
// --------------------------
// 组件构建
// --------------------------
build() {
NavDestination() { // 导航目标容器(弹窗模式)
Stack() {
// 1. 半透明背景
BlankBackground();
// 2. 主内容区
Column() {
// 2.1 顶部拖拽指示条
Row() {
Divider()
.height(4)
.width(48)
.borderRadius(2)
.backgroundColor($r('app.string.black_20')) // 20%透明度黑色
.margin({ top: 8 })
}.height(16).width(96).justifyContent(FlexAlign.Center)
// 2.2 标题栏
Row() {
Text($r('app.string.settings')) // 国际化文案
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.string.black_90')) // 90%黑色
Blank() // 占位空间
// 关闭按钮
Stack() {
Circle().fill('rgba(0,0,0,0.05)') // 圆形背景
Image($r('app.media.xmark')).height(18).width(18) // 关闭图标
}.onClick(() => RouterModule.pop()) // 点击关闭弹窗
}.height(40).width('100%')
// 2.3 快捷打卡开关
Row() {
Column() {
Text($r('app.string.quick_checkin')) // 主标题
.fontColor($r('app.string.black_90'))
.fontSize(18)
.height(24)
Text($r('app.string.quick_checkin_desc')) // 副标题
.fontColor($r('app.string.black_60'))
.fontSize(12)
.height(16)
}
// 开关组件
Toggle({
type: ToggleType.Switch,
isOn: this.isQuickCheckIn
}).onChange((isOn: boolean) => {
// 保存设置到服务器
RequestProxy.saveIsQuickCheckIn(isOn).then((value: BaseResponse<undefined>) => {})
})
}
.height(56)
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
// 内容区样式
.height(200)
.borderRadius({ topLeft: 32, topRight: 32 }) // 顶部圆角
.padding({ left: 16, right: 16 })
.backgroundColor($r('app.string.white_90')) // 90%透明度白色
.backdropBlur(54.3656005859375) // 背景模糊效果
}.alignContent(Alignment.Bottom) // 底部对齐
}
// 弹窗配置
.mode(NavDestinationMode.DIALOG) // 设置为弹窗模式
.onBackPressed(() => false) // 禁用返回键关闭
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) // 安全区域适配
.hideTitleBar(true) // 隐藏默认标题栏
.onShown(() => { // 弹窗显示时加载设置
RequestProxy.isQuickCheckIn().then((value: boolean) => {
this.isQuickCheckIn = value;
})
});
}
}
四、最终成果展示
