v0.2.0 沉浸式 + 按手机重排版 + 去掉导航模块

三条用户反馈一次处理完。

## ① 不够沉浸:首页距顶太远 + 底部白条

根因是**重复避让 + 颜色断裂**,两处都是我自己的错:
· 早先没开全屏时,系统已把窗口推到状态栏下方,我却又加了一个等高的白色
  Column「让出安全区」⇒ 重复避让,实测顶部空出 156px;
· 状态栏底色被设成「页面底色(宣纸米)」,而顶栏是白色 ⇒ 顶部出现
  「米色状态栏 + 白色顶栏」的拼接感,看着就是"没对齐"。

改法:
· EntryAbility 调 setWindowLayoutFullScreen(true),窗口铺满整屏;
· 状态栏底色一律取**顶栏底色**,底部手势条取**页面底色** —— 各自与紧邻元素同色;
· 页面侧用 getWindowAvoidArea 自己让位(顶栏顶部内边距 = 状态栏高度,
  底色一直画到屏幕最上沿);
· 底部那条全宽白 Column 删掉。

避让值走**异步** window.getLastWindow + windowSizeChange 监听
(早先"Ability 取窗存 AppStorage 再同步读"的做法实测读不到值,恒为 0);
旋转/折叠后会自动重算。

验证(像素级,非目测):y=0..200 全为顶栏白(原先 y=0..121 是米色状态条),
底部 y=2224..2444 全为纸色、白条消失。

## ② 去掉「导航」模块

用户原话:「导航是专门为电脑端开发的,都是网站,主要用在浏览器的主页,所以不需要」。
⇒ 删掉 FbNavPage、FbNavLink 类型、FB_DEMO_NAV、fbGroupNav、图标分支与演示数据。
⚠️ 模块清单自此与 Web 端 Module::LIST **有意不等**,注释里写明了别补回去。

## ③ 排版按手机重做(不照搬电脑端)

首页:删掉 hero 招牌整块(它只重复信息面板已有的信息),信息面板升为首块
并改成**无卡片的页面头部**(问候/日期大字、天气右上、三数字贴底)——
套白卡片会在首屏就切出一块白、压缩可用高度,也破坏沉浸感。
卡片从「今天的日程」才开始用,页面层次反而更清楚。

其余按手机重排:观影两列定格(原瀑布流)、任务按状态三段(原多列看板)、
家谱圈层(原折线树)。README 里列了逐项取舍与理由。

## 编译
hvigorw assembleHap --mode module -p product=default --no-daemon
→ BUILD SUCCESSFUL,0 error / 0 warning
This commit is contained in:
2026-10-11 23:20:49 +08:00
parent 41e3aa3d95
commit 0548a45da1
11 changed files with 307 additions and 370 deletions
+55 -83
View File
@@ -73,99 +73,88 @@ export struct FbHomePage {
Scroll() {
Column({ space: 0 }) {
// ==================== ① hero ====================
Row({ space: 12 }) {
Image($r('app.media.fb_logo'))
.width(52)
.height(52)
.borderRadius(14)
Column({ space: 3 }) {
Text(this.app.session.familyTitle)
.fontSize(FbMetric.fontH1)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
Text(this.app.session.slogan)
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.muted)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 两个快捷入口:我的资料 / 我的家谱
Row({ space: 8 }) {
this.heroAction($r('app.media.fb_ic_user'), 'people')
this.heroAction($r('app.media.fb_ic_kin'), 'kin')
}
}
.width('100%')
.padding({ left: FbMetric.pagePad, right: FbMetric.pagePad, top: 16, bottom: 14 })
.alignItems(VerticalAlign.Center)
// ==================== ② 信息面板 ====================
Column({ space: 12 }) {
// ==================== ① 头部(问候 + 今天 + 天气)====================
// 🔴 手机端排版要点:这一块**不套白卡片**,直接铺在纸底上 ——
// 它是"页面头部"而不是"一张内容卡"。套上卡片会在第一屏就切出一块白,
// 既压缩了首屏可用高度,也破坏了沉浸感(用户反馈「不够沉浸」)。
// 卡片从下面的「今天的日程」才开始用,页面层次反而更清楚。
Column({ space: 10 }) {
// 第一行:问候 + 名字(左) / 温度(右)
Row() {
Column({ space: 6 }) {
Column({ space: 5 }) {
Row({ space: 4 }) {
Text(this.hello())
.fontSize(FbMetric.fontBody)
.fontSize(22)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
Text(',' + this.app.session.me.name)
.fontSize(FbMetric.fontBody)
.fontColor(FbColors.muted)
.fontSize(22)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
}
.alignItems(VerticalAlign.Bottom)
// 日期 · 星期 · 农历(一行排开,手机上一行读得完)
Row({ space: 8 }) {
Text(this.dateLine())
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.ink)
.fontColor(FbColors.muted)
Text('八月廿二')
.fontSize(FbMetric.fontTiny)
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.faint)
}
// 日子标记(节气 / 节日 / 生日)
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(FB_DEMO_MARKS, (mk: string, idx: number) => {
FbTag({ text: mk, tone: idx === 0 ? 'green' : 'brand' })
.margin({ right: 6, top: 2 })
}, (mk: string, idx: number): string => 'mk_' + idx.toString() + '_' + mk)
}
.width('100%')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 天气靠右
Row({ space: 8 }) {
// 天气:靠右,温度大字 + 文案小字
Row({ space: 6 }) {
Image(this.weatherIcon())
.width(26)
.height(26)
.renderMode(ImageRenderMode.Template)
.fillColor(FbColors.brand2)
Column({ space: 0 }) {
Text(this.weather().temp.toString() + '°')
.fontSize(26)
.fontSize(24)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
Text(this.weather().text + ' · ' + this.weather().wind)
Text(this.weather().text)
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.muted)
.maxLines(1)
}
.alignItems(HorizontalAlign.End)
Image(this.weatherIcon())
.width(30)
.height(30)
.renderMode(ImageRenderMode.Template)
.fillColor(fbPalette('#B0763A').brand)
}
.alignItems(VerticalAlign.Center)
}
.width('100%')
.alignItems(VerticalAlign.Top)
Divider().color(FbColors.line2)
// 第二行:天气地点 + 日子标记(节气 / 节日 / 生日)
Column({ space: 6 }) {
Text(this.weather().place + ' · ' + this.weather().wind)
.fontSize(FbMetric.fontTiny)
.fontColor(FbColors.faint)
.maxLines(1)
.width('100%')
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(FB_DEMO_MARKS, (mk: string, idx: number) => {
FbTag({ text: mk, tone: idx === 0 ? 'green' : 'brand' })
.margin({ right: 6, top: 2 })
}, (mk: string, idx: number): string => 'mk_' + idx.toString() + '_' + mk)
}
.width('100%')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
// 第三行:三个数字(未来七天日程 / 待办 / 逾期)——
// 贴在头部末尾,作为"今天要不要操心的快速判断"
Divider().color(FbColors.line2).margin({ top: 2 })
FbStatTriple({
labelA: '未来七天日程',
labelA: '未来七天',
valueA: FB_DEMO_WEEK_STAT.events.toString(),
labelB: '待办',
valueB: FB_DEMO_WEEK_STAT.todos.toString(),
@@ -175,10 +164,13 @@ export struct FbHomePage {
})
}
.width('100%')
.padding(FbMetric.cardPad)
.backgroundColor(FbColors.surface)
.borderRadius(FbMetric.radius)
.margin({ left: FbMetric.pagePad, right: FbMetric.pagePad })
.padding({
left: FbMetric.pagePad,
right: FbMetric.pagePad,
top: 14,
bottom: 4
})
.alignItems(HorizontalAlign.Start)
// ==================== ③ 今天的日程 + 近期任务 ====================
Column({ space: 0 }) {
@@ -350,25 +342,6 @@ export struct FbHomePage {
.align(Alignment.TopStart)
}
/** hero 上的方形快捷入口 */
@Builder
heroAction(icon: Resource, target: string) {
Button({ type: ButtonType.ROUNDED_RECTANGLE }) {
Image(icon)
.width(20)
.height(20)
.renderMode(ImageRenderMode.Template)
.fillColor(FbColors.muted)
}
.width(40)
.height(40)
.backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS)
.onClick(() => {
this.app.switchModule(target);
})
}
/** 一块模块入口卡(图标 + 模块名 + 一句关键数字) */
@Builder
moduleCard(c: FbModuleCard) {
@@ -425,7 +398,6 @@ export struct FbHomePage {
case 'days': return $r('app.media.fb_ic_days');
case 'ledger': return $r('app.media.fb_ic_ledger');
case 'books': return $r('app.media.fb_ic_books');
case 'nav': return $r('app.media.fb_ic_nav');
case 'notes': return $r('app.media.fb_ic_notes');
default: return $r('app.media.fb_ic_home');
}