style(月/周视图): 今天也变大圆、周视图统一正圆、待办标签按需显示、今天按钮状态化 #6

用户提的四个细节,一次改完。

## 1. 今天的淡蓝底也要变大圆
原来 `isToday` 的淡蓝底贴在日期数字上(24×24 小圈),而选中态是 46vp 大圆。
同一天"选不选中"看起来像两种不同的东西。
现在两者尺寸统一:选中=实蓝圆,今天=淡蓝圆,都是 46vp。
日期数字自身的背景一律透明,避免"大圆里套小圈"。

## 2. 周视图选中态也变大圆
周条原来只有 30×30 的小圈,跟月视图 46vp 的大圆不一致。
同一个"选中"在两个视图里长得不一样,会让人以为是不同状态。
改用 Stack + 36vp 正方形 + 50% 圆角(周条比月历窄,36 够用且不压邻居)。

## 3. 没有待办就不显示「待办」标签
判定用 `this.todos.length > 0`。
todos 已按"可见日历本"过滤,所以这个判断等于"用户实际能看到几条待办"。
否则用户点进去一片空白,会以为功能坏了。

## 4. 「今天」按钮要能看出"在不在今天"
· 已在今天 → 透明底 + 蓝框蓝字(无需跳转)
· 不在今天 → 蓝底白字(可点,点了回今天)
新增 isOnToday() 判定:selectedDate === startOfDay(now)。

## 为什么圆一定要用 Stack
Column 是 layoutWeight(1) 撑满的**矩形**,圆角给再大也只是"圆角方块/胶囊"。
只有独立的正方形容器取 50% 圆角才是真圆。
这一点这轮改了两遍才对(第一版铺在 Column 上,得到 149×133 的方块)。
This commit is contained in:
2026-11-02 21:56:25 +08:00
parent b41eaabc41
commit 4f19c9482d
+53 -16
View File
@@ -1347,10 +1347,15 @@ struct Index {
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
.fontColor($r('app.color.text_primary')) .fontColor($r('app.color.text_primary'))
Blank() Blank()
// ⭐ 「今天」按钮要能看出"当前在不在今天":
// · 已在今天 → 透明底 + 蓝框蓝字(表示无需跳转)
// · 不在今天 → 蓝底白字(表示可点,点了回今天)
Button('今天') Button('今天')
.fontSize(12) .fontSize(12)
.fontColor($r('app.color.brand')) .fontColor(this.isOnToday()
.backgroundColor(Color.Transparent) ? $r('app.color.brand') : $r('app.color.button_text'))
.backgroundColor(this.isOnToday()
? Color.Transparent : $r('app.color.brand'))
.border({ width: 1, color: $r('app.color.brand'), radius: 14 }) .border({ width: 1, color: $r('app.color.brand'), radius: 14 })
.height(28) .height(28)
.padding({ left: 12, right: 12 }) .padding({ left: 12, right: 12 })
@@ -1476,8 +1481,12 @@ struct Index {
this.modeTab('month', '月') this.modeTab('month', '月')
this.modeTab('week', '周') this.modeTab('week', '周')
this.modeTab('agenda', '列表') this.modeTab('agenda', '列表')
// ⭐ TODO_TAB 待办页签:与列表同一套布局(未完成在前、已完成在后),点击可勾选完成 // ⭐ 待办页签按需显示:**没有待办就不显示**。
// 否则用户点进去一片空白,会以为功能坏了。
// todos 已按"可见日历本"过滤,所以这里判定 = 用户实际能看到的待办数。
if (this.todos.length > 0) {
this.modeTab('todo', '待办') this.modeTab('todo', '待办')
}
Blank() Blank()
if (this.mode === 'month') { if (this.mode === 'month') {
Text(this.fmtMonthTitle()) Text(this.fmtMonthTitle())
@@ -1684,6 +1693,23 @@ struct Index {
weekStrip() { weekStrip() {
Row({ space: 4 }) { Row({ space: 4 }) {
ForEach(this.weekStripDays(), (cell: MonthCell) => { ForEach(this.weekStripDays(), (cell: MonthCell) => {
// ⭐ WEEK_CIRCLE 与月视图统一:选中/今天都是正圆底。
// 原来这里选中只有 30×30 的小圈,跟月视图 46vp 的大圆不一致,
// 同一个"选中"在两个视图里长得不一样,会让人以为是不同状态。
Stack() {
if (cell.dateMs === this.selectedDate) {
Column()
.width(36)
.height(36)
.borderRadius('50%')
.backgroundColor($r('app.color.selected_bg'))
} else if (cell.isToday) {
Column()
.width(36)
.height(36)
.borderRadius('50%')
.backgroundColor($r('app.color.today_bg'))
}
Column({ space: 2 }) { Column({ space: 2 }) {
Text(WEEK_LABELS[(new Date(cell.dateMs).getDay() + 6) % 7]) Text(WEEK_LABELS[(new Date(cell.dateMs).getDay() + 6) % 7])
.fontSize(11) .fontSize(11)
@@ -1702,20 +1728,20 @@ struct Index {
.width(30) .width(30)
.height(30) .height(30)
.textAlign(TextAlign.Center) .textAlign(TextAlign.Center)
.borderRadius(15) // 背景交给底层圆(否则会出现"大圆套小圈")
.backgroundColor(cell.dateMs === this.selectedDate .backgroundColor(Color.Transparent)
? $r('app.color.selected_bg')
: (cell.isToday ? $r('app.color.today_bg') : Color.Transparent))
// ⭐ WEEK_DOT_BELOW 与月视图统一:农历保持原色,下方一个浅红小点。
// (两套标记会让人以为是不同含义,上次已踩过。)
Text(cell.lunar) Text(cell.lunar)
.fontSize(8) .fontSize(8)
.fontColor($r('app.color.text_hint')) .fontColor(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.text_hint'))
.maxLines(1) .maxLines(1)
Circle({ width: 3.5, height: 3.5 }) Circle({ width: 3.5, height: 3.5 })
.fill($r('app.color.soft_red')) .fill(cell.dateMs === this.selectedDate
? $r('app.color.button_text') : $r('app.color.soft_red'))
.opacity(cell.hasEvent ? 1 : 0) .opacity(cell.hasEvent ? 1 : 0)
} }
.justifyContent(FlexAlign.Center)
}
.layoutWeight(1) .layoutWeight(1)
.onClick(() => { .onClick(() => {
this.selectedDate = cell.dateMs; this.selectedDate = cell.dateMs;
@@ -2053,6 +2079,11 @@ struct Index {
} }
} }
/** 当前选中日是否就是今天(用于「今天」按钮的视觉状态) */
private isOnToday(): boolean {
return this.selectedDate === this.startOfDay(Date.now());
}
/** 回到本周(含今天) */ /** 回到本周(含今天) */
private goThisWeek(): void { private goThisWeek(): void {
this.selectedDate = this.startOfDay(Date.now()); this.selectedDate = this.startOfDay(Date.now());
@@ -3323,13 +3354,21 @@ struct Index {
@Builder @Builder
dayCellCircle(cell: MonthCell) { dayCellCircle(cell: MonthCell) {
Stack() { Stack() {
// 底层:选中时显示的正圆 // ⭐ TODAY_RING 底层圆:选中用实蓝,今天用淡蓝,尺寸一致。
// 原来今天只在日期数字上贴了个 24×24 的小圈,选中却是 46vp 大圆,
// 同一天"选不选中"看起来像两种东西。现在两者尺寸统一。
if (cell.dateMs === this.selectedDate) { if (cell.dateMs === this.selectedDate) {
Column() Column()
.width(this.wideLayout ? 40 : 46) .width(this.wideLayout ? 40 : 46)
.height(this.wideLayout ? 40 : 46) .height(this.wideLayout ? 40 : 46)
.borderRadius('50%') .borderRadius('50%')
.backgroundColor($r('app.color.selected_bg')) .backgroundColor($r('app.color.selected_bg'))
} else if (cell.isToday) {
Column()
.width(this.wideLayout ? 40 : 46)
.height(this.wideLayout ? 40 : 46)
.borderRadius('50%')
.backgroundColor($r('app.color.today_bg'))
} }
// 上层:原有内容(日期数字 / 农历 / 事件点) // 上层:原有内容(日期数字 / 农历 / 事件点)
Column({ space: 1 }) { Column({ space: 1 }) {
@@ -3345,10 +3384,8 @@ struct Index {
.height(this.wideLayout ? 22 : 24) .height(this.wideLayout ? 22 : 24)
.textAlign(TextAlign.Center) .textAlign(TextAlign.Center)
.borderRadius(this.wideLayout ? 11 : 12) .borderRadius(this.wideLayout ? 11 : 12)
// 选中时背景由底层的圆负责,这里透明 // 背景一律交给底层圆,这里保持透明(否则会出现"大圆里套小圈")
.backgroundColor(cell.dateMs === this.selectedDate .backgroundColor(Color.Transparent)
? Color.Transparent
: (cell.isToday ? $r('app.color.today_bg') : Color.Transparent))
if (!this.wideLayout) { if (!this.wideLayout) {
Text(cell.lunar) Text(cell.lunar)
.fontSize(8) .fontSize(8)