Skip to content

feat(home): 底栏切换改为水平滑动 - #145

Merged
Carinoasd merged 4 commits into
Carinoasd:masterfrom
bbtu1:feat/home-branch-slide
Sep 29, 2026
Merged

Carinoasd merged 4 commits into
Carinoasd:masterfrom
bbtu1:feat/home-branch-slide

Conversation

@bbtu1

@bbtu1 bbtu1 commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

把底栏分支的切换从「瞬间替换」改成「水平滑动」。

实现:

  • 新增 AnimatedBranchPageView:用 PageView 承载 StatefulShellRoute 的各分支,切换 tab 时 animateToPage 滑过去;
    每个分支仍各自持有自己的 Navigator 与页面状态(页面始终挂载、不重建、状态不丢)。
  • app_routes.dart:StatefulShellRoute.indexedStack → StatefulShellRoute + navigatorContainerBuilder。

说明:

  • PageView 关闭手势滑动(physics: NeverScrollableScrollPhysics),滑动只由底栏点击驱动,
    避免和各分支内部的列表 / 横向滑动控件抢手势。
  • 回归测试(切分支后 PageView 存在、索引走到 1、两个分支页面保持挂载)会紧接着补一个 commit。

The bottom navigation tabs used StatefulShellRoute.indexedStack, which swaps the branch instantly. Host the branches in a PageView (AnimatedBranchPageView) instead so the switch slides horizontally; every branch keeps its own navigator and page state because the pages stay mounted.
Three-branch shell, like the app: the switch animates the PageView, and a branch switched away from (even to the far one) keeps its page state instead of being rebuilt.
@Carinoasd

Carinoasd commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

感謝貢獻, 本機驗證過了: analyze 跟基線一樣, test_145 加上 test_171/test_174 共 55 項通過, 切分頁後狀態也確實有保留. 合併前麻煩修兩點:

  1. 沒顯示的分頁, 動畫要停掉. 原本的 StatefulShellRoute.indexedStack 會把沒顯示的分頁包成 Offstage + TickerMode(enabled: false), 改成 PageView 後這層沒了, 隱藏分頁裡的轉圈, 骨架閃爍等動畫會在背景一直跑. 建議在 AnimatedBranchPageView 裡對每個分頁包一層 TickerMode(enabled: index == widget.navigationShell.currentIndex, child: ...), 滑動途中要讓目標分頁能動.

  2. 系統開了減少動態效果時 (MediaQuery.disableAnimationsOf(context) 為 true), 請直接 jumpToPage, 不要播滑動.

另外測試檔名 test_145_... 跟現有的 test_145_poll_create_parser_test.dart 編號重複, 可以改成最新編號之後 (目前到 test_174), 這點不強制.

補完後請在測試各加一個案例, 我這邊再跑一次就合併, 謝謝!

- Every branch stays mounted in the PageView, so the ones that are off screen have to be muted by hand; the indexedStack container this replaced wrapped them in an Offstage with a disabled TickerMode.

- The shell reports the new branch before the slide starts, so the branch being slid to is the current one and keeps animating while it moves into view.
- The slide test file collided with test_145_poll_create_parser_test.dart, so it is numbered after the latest test now.

- One case counts the frames of an endless animation in every branch: the one left off screen must stop, the slide target must keep running while it moves in.

- One case asserts the reduced motion setting switches within a single frame, while the default still slides.
@bbtu1

bbtu1 commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

两点都改了,测试文件名也顺手换了,已推到 feat/home-branch-slide(ad511c27)。

1. 隐藏分页停止动画

  • AnimatedBranchPageView.build 现在给每个分页包一层 TickerMode(enabled: index == currentIndex, child: ...)。
  • 「滑动途中要让目标分页能跑动画」这点:goBranch() 会先把 currentIndex 更新成目标,之后才触发 didUpdateWidget 播动画,所以用 currentIndex 判断刚好就是「目标已启用」;注释里也写明了不能改用 _controller.page(动画期间它还停在旧页,会把目标冻住)。
  • 补的用例:每个分页跑一个常驻动画并数它的 tick 次数,留在屏幕外的那个必须停止,滑动中的目标必须继续。把修复收掉时这条会红(Expected: <7> Actual: <8>)。

2. 减少动态效果

  • MediaQuery.disableAnimationsOf(context) 为 true 时直接 jumpToPage,不播滑动。
  • 用例:只 pump 一帧就断言 controller.page == 2,并对照「动画开启时同一帧仍停在 0」。收掉修复时这条也会红(Expected: <2> Actual: <0.0>)。

3. 测试文件名

  • test_145_home_branch_slide_test.dart 与 test_145_poll_create_parser_test.dart 撞号,已改成 test_175_home_branch_slide_test.dart(现最新到 174)。

本机验证:flutter analyze 0 issue、dart ./scripts/check_strict_analyzing.dart 0、flutter test 1769 passed。麻烦再跑一次,谢谢!

@Carinoasd
Carinoasd merged commit 0434146 into Carinoasd:master Sep 29, 2026
5 checks passed
@Carinoasd

Copy link
Copy Markdown
Owner

感謝, 已合併. 本機完整測試 1769 通過, analyze 跟基線一樣, 會隨下一個正式版發布.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants