You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GoRouter的ShellRoute中实现SliverAppBar的展开/折叠?

在GoRouter ShellRoute中实现可折叠SliverAppBar的滚动控制器问题

背景

我需要实现顶部带有可折叠SliverAppBar的页面,下方承载GoRouter各路由的内容。但GoRoute的builder只能返回Widget,无法直接返回Sliver,因此在ShellRoute的父级嵌套了CustomScrollView来整合路由内容。

遇到的问题

想要让路由页面滚动时,Shell里的SliverAppBar同步折叠,直接共享ScrollController触发了如下报错:

======== Exception caught by animation library =====================================================
The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is currently attached to more than one ScrollPosition.

The Scrollbar requires a single ScrollPosition in order to be painted.

When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition attached.The provided ScrollController must be unique to one ScrollView widget.

解决方法

方案一:将路由内容包装为Sliver(优先推荐)

把路由页面用SliverToBoxAdapter包裹,作为Shell层CustomScrollView的Sliver列表项,整个滚动区域共用一个ScrollController,自然实现滚动联动:

ShellRoute(
  builder: (context, state, child) {
    final scrollController = ScrollController();
    return CustomScrollView(
      controller: scrollController,
      slivers: [
        SliverAppBar(
          title: const Text('可折叠标题'),
          expandedHeight: 200,
          pinned: true,
        ),
        // 把路由页面转为Sliver加入滚动列表
        SliverToBoxAdapter(child: child),
      ],
    );
  },
  routes: [
    GoRoute(
      path: '/page1',
      builder: (context, state) => Page1(), // Page1为普通Widget,内部滚动组件无需单独控制器
    ),
    // 其他路由配置
  ],
);

方案二:通过滚动通知同步状态

如果路由页面必须使用独立的ScrollView,可以在Shell层监听子组件的滚动通知,同步控制SliverAppBar的折叠状态:

ShellRoute(
  builder: (context, state, child) {
    final scrollController = ScrollController();
    return NotificationListener<ScrollNotification>(
      onNotification: (notification) {
        if (notification is ScrollUpdateNotification) {
          // 同步子页面的滚动偏移到Shell的控制器
          scrollController.jumpTo(scrollController.offset + notification.scrollDelta!);
        }
        return false;
      },
      child: CustomScrollView(
        controller: scrollController,
        slivers: [
          SliverAppBar(
            title: const Text('可折叠标题'),
            expandedHeight: 200,
            pinned: true,
          ),
          SliverToBoxAdapter(child: child),
        ],
      ),
    );
  },
  routes: [
    GoRoute(
      path: '/page1',
      builder: (context, state) => Page1(), // Page1内部有独立ScrollView
    ),
  ],
);

注:该方案可能存在滚动同步延迟,优先选择方案一。

内容的提问来源于stack exchange,提问作者friend.code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:33:27