From 39337a55302528e82498cfd85ebbc5784e6ab6f7 Mon Sep 17 00:00:00 2001 From: laoyang Date: Thu, 5 Nov 2026 10:55:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=BE=85=E5=8A=9E):=20=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8=E6=94=B9=E4=B8=BA=E5=B1=85=E4=B8=AD=E5=BC=B9=E5=B1=82?= =?UTF-8?q?=20+=20=E5=AF=B9=E5=8B=BE=E6=94=B9=E7=9F=A2=E9=87=8F=E7=BB=98?= =?UTF-8?q?=E5=88=B6=20(#50)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 1. 时间选择器改为屏幕居中弹出 ### 用户诉求 「点完开始之后,在中间弹出一个框来选择时间,操作起来更方便」 ### 为什么不用 bindSheet 查 SDK `SheetOptions`(common.d.ts:11753)确认:**没有 position / alignment 参数**, bindSheet 只能从底部弹,无法居中。 ### 做法:自绘居中覆盖层 把 build() 根节点改为 `Stack`: Stack(alignContent: Center) { Column { 顶部栏 + Scroll 表单 } ← 原有内容 if (sheetShow) { 遮罩(半透明,点空白关闭) centerDialog() ← 居中卡片 } } 选这条路而不是 CustomDialogController,依据是本工程 MEMORY: 系统弹层在本环境曾"静默失败"(Index.ets:1421 已记录), 首启引导页 tipsOverlay 就是改用自绘覆盖层才可靠的。 ## 2. 对勾改为矢量 Path ### 问题 原来用字符 `✓`(U+2713),三个毛病: - 字体依赖:不同设备粗细/形状不同 - 粗细不可控:fontWeight 对符号字形影响有限 - 居中不稳:字形基线导致视觉重心偏移 ### 改法 用 `Path` 画折线,配 strokeWidth + 圆头圆角: commands('M6 12.5 L9.5 16 L16.5 8') // 22vp 列表 commands('M5 9.5 L7.5 12.5 L13 6.5') // 18vp 时间轴 得到粗细均匀、端点圆润、可精确居中的勾。 两处统一:待办列表勾选圈、时间轴待办区勾选圈。 ## 编译 BUILD SUCCESSFUL ## 真机验证(5NC0225B27004718) | 验证项 | 实测 | |---|---| | 弹层居中 | 弹层 y 750~1728,中心 **1239**;屏幕中心 1222,偏差仅 17px | | 对比改造前 | 中心 1800(偏下 578px)→ 现在偏 17px | | 日期/时间滚轮 | `DatePicker 2026年11月5日` + `TimePicker 09:00` 正常渲染 | | 对勾 Path 数量 | 1 个 `[96,2013][165,2082]` | | 字符 ✓ 残留 | 0 个 | --- entry/src/main/ets/pages/Index.ets | 60 ++++++++++++------- entry/src/main/ets/pages/TodoEditPage.ets | 71 +++++++++++++++-------- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index a9056f7..e84ef98 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -3498,14 +3498,24 @@ struct Index { // 勾选框(颜色跟随日历本)—— **只有这块触发完成切换** Row() { if (t.completed) { - Text('✓') - .fontSize(13) - .fontColor($r('app.color.button_text')) - .width(22) - .height(22) - .textAlign(TextAlign.Center) - .borderRadius(11) - .backgroundColor(this.colorOfCal(t.calKey)) + // ⭐ 用矢量 Path 画勾(#50):字符 '✓' 依赖字体, + // 不同设备下粗细/居中不一致,视觉上"不精致"。 + // Path 可精确控制线宽、端点圆角与几何比例。 + Stack() { + Path() + .width(22) + .height(22) + .commands('M6 12.5 L9.5 16 L16.5 8') + .stroke($r('app.color.button_text')) + .strokeWidth(2.2) + .strokeLineCap(LineCapStyle.Round) + .strokeLineJoin(LineJoinStyle.Round) + .fill(Color.Transparent) + } + .width(22) + .height(22) + .borderRadius(11) + .backgroundColor(this.colorOfCal(t.calKey)) } else { Text('') .width(22) @@ -4594,18 +4604,28 @@ struct DayTimelineView { ForEach(this.timeline.todos, (td: DisplayEvent) => { Row({ space: 8 }) { // 勾选圈:点击切换完成(与待办列表同一回调) - Text(td.completed ? '✓' : '') - .fontSize(12) - .fontColor(td.completed ? '#FFFFFF' : 'rgba(0,0,0,0)') - .width(18) - .height(18) - .textAlign(TextAlign.Center) - .borderRadius(9) - .backgroundColor(td.completed ? td.color : 'rgba(0,0,0,0)') - .border({ width: 1.5, color: td.color }) - .onClick(() => { - this.onToggleTodo(td); - }) + // 同列表:矢量勾(#50) + Stack() { + if (td.completed) { + Path() + .width(18) + .height(18) + .commands('M5 9.5 L7.5 12.5 L13 6.5') + .stroke('#FFFFFF') + .strokeWidth(2) + .strokeLineCap(LineCapStyle.Round) + .strokeLineJoin(LineJoinStyle.Round) + .fill(Color.Transparent) + } + } + .width(18) + .height(18) + .borderRadius(9) + .backgroundColor(td.completed ? td.color : 'rgba(0,0,0,0)') + .border({ width: 1.5, color: td.color }) + .onClick(() => { + this.onToggleTodo(td); + }) Text(td.title === '' ? '(无标题待办)' : td.title) .fontSize(12) .fontColor($r('app.color.text_primary')) diff --git a/entry/src/main/ets/pages/TodoEditPage.ets b/entry/src/main/ets/pages/TodoEditPage.ets index 6af0aae..d580c78 100644 --- a/entry/src/main/ets/pages/TodoEditPage.ets +++ b/entry/src/main/ets/pages/TodoEditPage.ets @@ -521,7 +521,8 @@ struct TodoEditPage { // ---------- UI ---------- build() { - Column({ space: 14 }) { + Stack({ alignContent: Alignment.Center }) { + Column({ space: 14 }) { // ===== 固定顶部栏:取消 · 标题 · 保存 ===== Row({ space: 6 }) { Text('取消') @@ -850,35 +851,54 @@ struct TodoEditPage { .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) .align(Alignment.Top) + } + .width('100%') + .height('100%') + .padding({ top: 12 }) + .backgroundColor($r('app.color.page_bg')) + // ⭐ 沉浸式:背景延伸到状态栏/导航条区域(与 EventEditPage 一致) + // 只扩绘制范围、不移动子组件 → 状态栏区域同色,不再是割裂的白条 + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) + + // ===== 居中弹层(浮在内容之上)===== + if (this.sheetShow) { + // 遮罩:半透明,点空白关闭 + Column() + .width('100%') + .height('100%') + .backgroundColor('#66000000') + .onClick(() => { + this.sheetShow = false; + }) + // 居中卡片 + this.centerDialog() + } } .width('100%') .height('100%') - .padding({ top: 12 }) - .backgroundColor($r('app.color.page_bg')) - // ⭐ 沉浸式:背景延伸到状态栏/导航条区域(与 EventEditPage 一致) - // 只扩绘制范围、不移动子组件 → 状态栏区域同色,不再是割裂的白条 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) - .bindSheet($$this.sheetShow, this.bottomSheet(), { - height: this.sheetMode === 'parent' ? 400 : 380, - showClose: false, - dragBar: true, - backgroundColor: $r('app.color.card_bg') - }) } - /** 唯一底部弹层:按 sheetMode 切换内容 */ + /** + * 居中弹层(自绘覆盖层,不用 bindSheet)。 + * + * 为什么不用 bindSheet:SDK 的 SheetOptions 没有 position/alignment, + * 只能从底部弹,无法居中。而用户要求"在中间弹出来更方便"。 + * 本工程既有的 tipsOverlay 也是自绘覆盖层(系统弹层在本环境不可靠), + * 这里沿用同一套做法。 + */ @Builder - bottomSheet() { + centerDialog() { if (this.sheetMode === 'parent') { - this.parentSheet() + this.parentDialog() } else { - this.dueSheet() + this.dueDialog() } } - /** 截止时间选择弹层(日期 + 时间) */ + /** 截止时间选择弹层(居中卡片:日期 + 时间) */ @Builder - dueSheet() { + dueDialog() { Column({ space: 14 }) { Text('选择截止时间') .fontSize(16) @@ -935,13 +955,15 @@ struct TodoEditPage { this.sheetShow = false; }) } - .width('100%') - .padding({ left: 16, right: 16, bottom: 24 }) + .width('86%') + .padding(18) + .borderRadius(16) + .backgroundColor($r('app.color.card_bg')) } - /** 父任务选择弹层 */ + /** 父任务选择弹层(居中卡片) */ @Builder - parentSheet() { + parentDialog() { Column({ space: 10 }) { Row({ space: 8 }) { Text('选择父任务') @@ -1011,9 +1033,10 @@ struct TodoEditPage { this.sheetShow = false; }) } - .width('100%') - .padding({ left: 16, right: 16, bottom: 24 }) - .layoutWeight(1) + .width('86%') + .padding(18) + .borderRadius(16) + .backgroundColor($r('app.color.card_bg')) } /** 确认截止时间:把滚轮值合成毫秒 */