fix(周视图): 修复复用后颜色过浅、星期标签丢失 #6

用户反馈:周视图复用月视图后,日期/文字颜色太浅(灰),选中也不变白。

## 根因:weekStripDays 从未设置 inMonth
dayCellCircle 的颜色分支是:
    .fontColor(!cell.inMonth ? text_hint(灰) : ...)
但 weekStripDays() 只设了 dateMs/day/isToday/lunar/hasEvent,
**inMonth 一直是默认值 false** ⇒ 周条每天都被当成"非本月",全部走灰色分支。

修法:weekStripDays 里显式 `cell.inMonth = true`
(周条 7 天都是有效日期,没有"月外"概念)。

## 顺带补回丢失的星期标签
复用 dayCellCircle 时,原来周条自己那行 WEEK_LABELS(一/二/三…)被一并删掉了,
现在周条没有星期。
做法:dayCellCircle 加参数 `showWeekLabel`(默认 false),
周条传 true。月视图的星期在表头单独一行、不在格子里,所以默认不显示。

## 农历提亮
实测采样(JPEG,最暗 25%):
  周条农历 rgb(175~183)  ← text_hint(#4D000000)
  月历日期 rgb(27~54)    ← text_primary(#182431)
周条里农历紧挨日期数字,对比过强会显"糊"。
周条农历改用 text_secondary(约 rgb(120~150))、字号 8→9;
月视图农历保持 text_hint,不破坏已有观感。

## 教训
复用组件时必须核对**数据契约**:dayCellCircle 依赖 inMonth 决定颜色,
而 weekStripDays 从没提供这个字段。
"能编译、能显示"不等于"语义正确" —— 默认值 false 这种静默错误最难发现。
This commit is contained in:
2026-11-02 22:06:15 +08:00
parent 22db069bee
commit 2cc3b1ba42
+29 -62
View File
@@ -1691,65 +1691,15 @@ struct Index {
/** 周条:周一到周日(周视图顶部 / 复用) */ /** 周条:周一到周日(周视图顶部 / 复用) */
@Builder @Builder
weekStrip() { weekStrip() {
Row({ space: 4 }) { // 间距与月视图保持一致(space: 2):周条原来用 4,7 天多吃了 12px,
// 每格从 149 缩到 133,圆就只能跟着变小 —— 这才是"圆不够大"的根因。
Row({ space: 2 }) {
// ⭐ WEEK_REUSE 直接复用月视图的日期格 dayCellCircle,不再单独实现。
// 周条一行就是 7 天,和月视图一行结构完全相同,另写一套只会不一致
// (之前就因为圆的大小/字号/间距三处各调一遍,怎么调都对不齐)。
// 复用后选中圆、今天圆、农历、事件点天然与月视图一致。
ForEach(this.weekStripDays(), (cell: MonthCell) => { ForEach(this.weekStripDays(), (cell: MonthCell) => {
// ⭐ WEEK_CIRCLE 与月视图统一:选中/今天都是正圆底。 this.dayCellCircle(cell, true)
// 原来这里选中只有 30×30 的小圈,跟月视图 46vp 的大圆不一致,
// 同一个"选中"在两个视图里长得不一样,会让人以为是不同状态。
Stack() {
// ⭐ WEEK_BIGGER 圆必须够大:实测周条每列 133×192px,
// 原来只给 36vp(≈113px),比月视图的 138px 还小,看着空。
// 但**列宽 133px ≈ 44vp 是硬上限**,给 52 会横向溢出被裁切,
// 所以取 42vp(≈126px),留 7px 余量。
if (cell.dateMs === this.selectedDate) {
Column()
.width(42)
.height(42)
.borderRadius('50%')
.backgroundColor($r('app.color.selected_bg'))
} else if (cell.isToday) {
Column()
.width(42)
.height(42)
.borderRadius('50%')
.backgroundColor($r('app.color.today_bg'))
}
Column({ space: 2 }) {
Text(WEEK_LABELS[(new Date(cell.dateMs).getDay() + 6) % 7])
.fontSize(11)
// ⚠️ 这里原来用 button_text(纯白),但该标签**没有背景**、坐在页面底色上,
// 浅色模式下是"白字压浅灰底"→ 对比度仅 1.11:1(应用市场 UX 检测被判不合格)。
// 改用 brand_text(品牌色文字版):浅 #0057C2 → 6.01:1,深 #4DA3FF → 8.0:1,
// 既保留"选中"的强调含义,又满足对比度要求。
.fontColor(cell.dateMs === this.selectedDate
? $r('app.color.brand_text') : $r('app.color.text_hint'))
Text(String(cell.day))
.fontSize(16)
.fontWeight(cell.dateMs === this.selectedDate || cell.isToday
? FontWeight.Bold : FontWeight.Normal)
.fontColor(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.text_primary'))
.width(34)
.height(34)
.textAlign(TextAlign.Center)
// 背景交给底层圆(否则会出现"大圆套小圈")
.backgroundColor(Color.Transparent)
Text(cell.lunar)
.fontSize(9)
.fontColor(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.text_hint'))
.maxLines(1)
Circle({ width: 4, height: 4 })
.fill(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.soft_red'))
.opacity(cell.hasEvent ? 1 : 0)
}
.justifyContent(FlexAlign.Center)
}
.layoutWeight(1)
.onClick(() => {
this.selectedDate = cell.dateMs;
})
}, (cell: MonthCell) => `${cell.dateMs}_${cell.dateMs === this.selectedDate}` }, (cell: MonthCell) => `${cell.dateMs}_${cell.dateMs === this.selectedDate}`
+ `_he${cell.hasEvent ? 1 : 0}_td${cell.isToday ? 1 : 0}`) + `_he${cell.hasEvent ? 1 : 0}_td${cell.isToday ? 1 : 0}`)
} }
@@ -1782,6 +1732,10 @@ struct Index {
cell.isToday = dateMs === todayStart; cell.isToday = dateMs === todayStart;
cell.lunar = LunarUtil.lunarDayText(dateMs); cell.lunar = LunarUtil.lunarDayText(dateMs);
cell.hasEvent = eventDays.has(this.startOfDay(dateMs)); cell.hasEvent = eventDays.has(this.startOfDay(dateMs));
// ⭐ WEEK_INMONTH 周条里 7 天都是有效日期,没有"本月外"的概念,
// 必须显式设 true。否则复用 dayCellCircle 时 inMonth 默认 false,
// 日期会全部走进"非本月"分支显示成灰色,选中也不变白。
cell.inMonth = true;
cells.push(cell); cells.push(cell);
} }
return cells; return cells;
@@ -3356,7 +3310,7 @@ struct Index {
* 这一版用 46vp 正方形 → 真正的圆 * 这一版用 46vp 正方形 → 真正的圆
*/ */
@Builder @Builder
dayCellCircle(cell: MonthCell) { dayCellCircle(cell: MonthCell, showWeekLabel: boolean = false) {
Stack() { Stack() {
// ⭐ TODAY_RING 底层圆:选中用实蓝,今天用淡蓝,尺寸一致。 // ⭐ TODAY_RING 底层圆:选中用实蓝,今天用淡蓝,尺寸一致。
// 原来今天只在日期数字上贴了个 24×24 的小圈,选中却是 46vp 大圆, // 原来今天只在日期数字上贴了个 24×24 的小圈,选中却是 46vp 大圆,
@@ -3374,8 +3328,16 @@ struct Index {
.borderRadius('50%') .borderRadius('50%')
.backgroundColor($r('app.color.today_bg')) .backgroundColor($r('app.color.today_bg'))
} }
// 上层:原有内容(日期数字 / 农历 / 事件点) // 上层:原有内容(星期标签 / 日期数字 / 农历 / 事件点)
Column({ space: 1 }) { Column({ space: 1 }) {
// ⭐ 周条需要星期标签(一/二/三…),月视图的星期在表头单独一行、
// 不在这里,所以用参数控制,默认不显示以免破坏月视图布局。
if (showWeekLabel) {
Text(WEEK_LABELS[(new Date(cell.dateMs).getDay() + 6) % 7])
.fontSize(10)
.fontColor(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.text_secondary'))
}
Text(String(cell.day)) Text(String(cell.day))
.fontSize(this.wideLayout ? 12 : 13) .fontSize(this.wideLayout ? 12 : 13)
.fontWeight(cell.isToday || cell.dateMs === this.selectedDate .fontWeight(cell.isToday || cell.dateMs === this.selectedDate
@@ -3391,10 +3353,15 @@ struct Index {
// 背景一律交给底层圆,这里保持透明(否则会出现"大圆里套小圈") // 背景一律交给底层圆,这里保持透明(否则会出现"大圆里套小圈")
.backgroundColor(Color.Transparent) .backgroundColor(Color.Transparent)
if (!this.wideLayout) { if (!this.wideLayout) {
// ⭐ WEEK_LUNAR_BRIGHT 周条的农历提亮一档:
// 周条是"一周概览",农历紧挨日期数字,用 text_hint(#4D000000)
// 会显得比日期淡太多(实测 rgb≈178 vs 日期 rgb≈40)。
// 周条用 text_secondary,月历保持 text_hint(不破坏已有观感)。
Text(cell.lunar) Text(cell.lunar)
.fontSize(8) .fontSize(showWeekLabel ? 9 : 8)
.fontColor(cell.dateMs === this.selectedDate .fontColor(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.text_hint')) ? $r('app.color.button_text')
: (showWeekLabel ? $r('app.color.text_secondary') : $r('app.color.text_hint')))
.maxLines(1) .maxLines(1)
} }
Circle({ width: this.wideLayout ? 4 : 3.5, height: this.wideLayout ? 4 : 3.5 }) Circle({ width: this.wideLayout ? 4 : 3.5, height: this.wideLayout ? 4 : 3.5 })