首页 > 解决方案 > CustomScrollView 中的多个 SliverAppBar

问题描述

我需要有多个 SliverAppBar,每个在一个视图中都有自己的 SliverList。目前只有第一个 SliverAppBar 正确响应。

当然,我已经在 SO 和 Google 上进行了扩展搜索,但还没有找到解决方案!

  @override
  Widget build(BuildContext context) {
     return Scaffold(
        appBar: AppBar(
          title: Text('Details'),
        ),
        body: CustomScrollView(
          slivers: <Widget>[
            new SliverAppBar(
              floating: true,
              automaticallyImplyLeading: false,
              title: Text('1'),
            ),
            new SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(title: Text('Text 1')),
                childCount: 20,
              ),
            ),
            new SliverAppBar(
              automaticallyImplyLeading: false,
              title: Text('2'),
              floating: true,
            ),
            new SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => ListTile(title: Text('Text 2')),
                childCount: 20,
              ),
            ),
          ],
        ),
      );
  }

如果您滚动,我希望在您滚动列表时看到标题“2”也浮动。

标签: flutterflutter-sliver

解决方案


这似乎是一个限制CustomScrollView。可以解决这个问题,但这非常棘手,除非您有固定高度的项目和固定长度的列表。如果是这样,您可以假设整个会话的AppBar高度(每个列表项的高度 + 高度)。

看一看:

class Foo extends StatefulWidget {
  @override
  _FooState createState() => _FooState();
}

class _FooState extends State<Foo> {
  static const double listItemHeight = 50;
  static const int listItemCount = 15;

  static const double sessionHeight = kToolbarHeight + (listItemCount * listItemHeight);

  int floatingAppBarIndex;
  ScrollController controller;

  @override
  void initState() {
    super.initState();
    floatingAppBarIndex = 0;
    controller = ScrollController()..addListener(onScroll);
  }

  void onScroll() {
    double scrollOffset = controller.offset;
    int sessionsScrolled = 0;

    while (scrollOffset > sessionHeight) {
      scrollOffset -= sessionHeight;
      sessionsScrolled++;
    }

    if (sessionsScrolled != floatingAppBarIndex) {
      setState(() {
        floatingAppBarIndex = sessionsScrolled;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Details'),
      ),
      body: CustomScrollView(
        controller: controller,
        slivers: <Widget>[
          new SliverAppBar(
            floating: floatingAppBarIndex == 0,
            automaticallyImplyLeading: false,
            title: Text('1'),
          ),
          new SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return SizedBox(
                  height: listItemHeight,
                  child: ListTile(
                    title: Text('Text 1'),
                  ),
                );
              },
              childCount: listItemCount,
            ),
          ),
          new SliverAppBar(
            floating: floatingAppBarIndex == 1,
            automaticallyImplyLeading: false,
            title: Text('2'),
          ),
          new SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return SizedBox(
                  height: listItemHeight,
                  child: ListTile(
                    title: Text('Text 2'),
                  ),
                );
              },
              childCount: listItemCount,
            ),
          ),
        ],
      ),
    );
  }
}

正如我所说,您仍然可以在具有可变值(项目高度和列表长度)的列表中执行此操作,但这将非常非常棘手。如果这是您的情况,我建议使用以下插件之一: https ://pub.dartlang.org/packages/sticky_headers https://pub.dartlang.org/packages/flutter_sticky_header


推荐阅读