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

如何让ShellRoute子路由滚动时控制SliverAppBar的显示/隐藏/浮动?

解决Go Router ShellRoute中SliverAppBar随子路由滚动联动的问题

问题原因

当前你的DashboardScreen中,NestedScrollView直接将子路由(widget.child)作为body,但子路由的滚动控件是独立的,NestedScrollView无法感知其滚动状态,导致SliverAppBar的浮动、隐藏效果无法触发。

解决方案

要实现联动,需要让子路由的滚动内容与NestedScrollView的滚动系统关联,具体分两步:

1. 修改DashboardScreen的NestedScrollView配置

在headerSliverBuilder中添加SliverOverlapAbsorber,用于处理SliverAppBar的重叠区域,确保滚动状态能被正确传递:

DefaultTabController(
  length: 6,
  child: Scaffold(
    bottomNavigationBar: bottomMenuBuilder(context),
    padding: EdgeInsets.zero,
    body: NestedScrollView(
      floatHeaderSlivers: true,
      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[
          SliverOverlapAbsorber(
            // 关联NestedScrollView的handle
            handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
            sliver: const SliverAppBar(
              title: Text("floating appbar"),
              centerTitle: false,
              automaticallyImplyLeading: false,
              floating: true,
              // 如果需要收缩隐藏效果,添加以下配置
              // pinned: true,
              // expandedHeight: 200,
              // flexibleSpace: FlexibleSpaceBar(background: FlutterLogo()),
              actions: [
                Icon(Icons.search, size: 30, color: Colors.white),
              ],
              elevation: 0.0,
            ),
          ),
        ];
      },
      body: widget.child,
    ),
  ),
)

2. 改造子路由页面的滚动结构

子路由页面需要使用CustomScrollView包裹内容,并添加SliverOverlapInjector来接收DashboardScreen传递的滚动状态:

方式一:使用Sliver组件(推荐)

直接用SliverList/SliverGrid构建滚动内容:

class ChildRoutePage extends StatelessWidget {
  const ChildRoutePage({super.key});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        // 注入重叠处理,关联父级NestedScrollView
        SliverOverlapInjector(
          handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
        ),
        // 滚动内容
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) => ListTile(title: Text("列表项 $index")),
            childCount: 50,
          ),
        ),
      ],
    );
  }
}

方式二:适配普通ListView

如果要保留原有的ListView,需要将其放入SliverToBoxAdapter,并禁用自身滚动:

class ChildRoutePage extends StatelessWidget {
  const ChildRoutePage({super.key});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverOverlapInjector(
          handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
        ),
        SliverToBoxAdapter(
          child: ListView.builder(
            shrinkWrap: true,
            // 禁止ListView自身滚动,交由CustomScrollView处理
            physics: const NeverScrollableScrollPhysics(),
            itemCount: 50,
            itemBuilder: (context, index) => ListTile(title: Text("列表项 $index")),
          ),
        ),
      ],
    );
  }
}

效果说明

  • 开启floating: true:子路由向下滚动时,AppBar会自动隐藏;向上滚动时,AppBar会立即浮动显示。
  • 配合pinned: true和expandedHeight:AppBar会在滚动时收缩至仅保留标题栏,向上滚动时展开恢复。

内容的提问来源于stack exchange,提问作者RedsVision

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:17:57