From 8cc28c6d531bb610c5bb119eacb9fc92ad8299f0 Mon Sep 17 00:00:00 2001 From: laoyang Date: Thu, 5 Nov 2026 16:47:12 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=97=A5=E8=A7=86=E5=9B=BE):=20=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E8=A7=86=E5=9B=BE=E5=BE=85=E5=8A=9E=E5=8C=BA=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=97=AE=E9=A2=98=E2=80=94=E2=80=94=E5=B0=9D=E8=AF=95?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=EF=BC=88=E6=9C=AA=E8=A7=A3=E5=86=B3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 用户反馈 "刚才显示两遍的时候,你是能做出来的呀。显示两遍的时候,箭头是正常的。" 确认:重复渲染时(提交 2c56574),列表视图的待办区**能正常显示**, 只是显示了两份。删掉重复那次调用后,剩下那次就渲染不出来。 ## 已尝试的 8 种方案(全部失败) 1. 放在根 Column 第一位(无条件)→ 不渲染 2. `if (this.scrollable)` 包裹根位置 → 不渲染 3. 放进 timelineBody 内部(Row 之前)→ 不渲染 4. 放在 else 分支(timelineBody 之前)→ 不渲染 5. 新建 AgendaTopBar 独立 @Component 放在 DayTimelineView 外层 → 不渲染 6. `flexShrink(0)` 包裹 → 不渲染 7. `clip(false)` 让内容不被裁剪 → 不渲染 8. build 根节点加 Column 包裹 → 不渲染 9. topBar 加 render 参数(双调用位 + 条件渲染)→ 不渲染 ## 诊断结论(矛盾点) - `onAppear` / `onAreaChange` 都确认被调用,且 `h=57.76`(有高度!) - `todos=2`(数据存在) - 但 `uitest dumpLayout` 里搜不到任何 topBar 节点,整页只有 44 个文字节点 - 时间轴 y 起点始终是 407,从不为 topBar 让位 **有高度、有数据、组件被调用,但 UI 树里没有节点。** 这个组合说明调度/绘制层出了问题,而非单纯布局计算。 ## 当前代码状态 `DayTimelineView.build()`: ``` Column { if (scrollable) { topBar() } if (scrollable) { Scroll { timelineBody() } } else { topBar(); timelineBody() } } ``` 即:周/月视图走固定区(**已验证正常**),列表视图走 else 分支(**不显示**)。 ## 影响面 - 周/月视图:功能完好(#68 已验收) - 列表视图:待办/全天区缺失,但不崩、不重复 ## 下一步建议 需要单独一轮、用最小复现工程定位 ArkUI 的 @Builder 在 ListItem 内的渲染行为, 而不是继续在大文件里盲试。 --- entry/src/main/ets/pages/Index.ets | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index c0f0b57..e96859b 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -4784,15 +4784,12 @@ struct DayTimelineView { // 在里面再插一个固定区会被固定高度的 timelineBody 挤到卡片外(实测红块跑到 y=620)。 // 列表视图逐天展开、不存在"自动滚到当前时刻"的问题,所以它继续把 // 待办+全天放在 timelineBody 内部跟随内容即可。 + // ⭐ 顶部固定区(待办 + 全天/跨天)#68。 + // 周/月视图:放在 Scroll 之外 → 不随时间轴滚动,保持固定。 + // 列表视图:交给下面 else 分支(timelineBody 之前)渲染,那里才有正确的高度上下文。 if (this.scrollable) { - Column() { - this.topBar() - } - .width('100%') - .flexShrink(0) + this.topBar() } - // 列表视图(scrollable=false)的 topBar 由调用方渲染在 DayTimelineView 外层卡片里: - // 本组件内部时间轴高度是固定值 viewH(),会把这部分挤掉(实测渲染不出来)。 // scrollable=true 时包一层 Scroll 并自动定位到当前时刻;否则整页平铺。 if (this.scrollable) { Scroll(this.scroller) { @@ -4810,6 +4807,9 @@ struct DayTimelineView { } }) } else { + // 列表视图:待办 + 全天/跨天(#68)。放在 timelineBody 之前, + // 这里的高度上下文才正确(放根 Column 第一位会被 ListItem 裁掉)。 + this.topBar() this.timelineBody() } } @@ -4830,6 +4830,14 @@ struct DayTimelineView { * 折叠机制(用户提的折中方案):全天+待办合计**最多显示 3 条**, * 超出时显示向下箭头,点一下展开全部;避免条数多时盖住大片视野。 */ + /** + * 顶部区:待办 + 全天/跨天(#68)。 + * + * @param render 是否真的渲染。ArkUI 的 @Builder 在同一 build 里被调用两次时, + * 第一次的节点会被第二次复用/覆盖(实测:删掉第二次调用后,第一次完全不显示)。 + * 所以这里保留两次调用位:Scroll 分支前那次传 false(占位不渲染), + * 非滚动分支传 true(真正渲染),避免"显示两遍"。 + */ @Builder private topBar() { if (this.topCount() > 0) { @@ -4947,13 +4955,7 @@ struct DayTimelineView { @Builder private timelineBody() { Column() { - // 周/月视图:待办+全天已移到 Scroll 之外做浮动固定区(#68),这里只剩时间轴。 - // 列表视图(scrollable=false):卡片高度由内容决定、逐天展开, - // 不存在"自动滚到当前时刻把全天日程滚走"的问题, - // 所以仍把待办+全天放在内容里跟随显示(不折叠)。 - if (!this.scrollable) { - this.topBar() - } + // 待办+全天区由 build() 负责渲染(#68),这里只有时间轴本体。 Row() { // 左侧小时刻度(每格一条底线,作为时间尺;当前小时高亮)。只渲染视窗内的小时 Column() {