【问题标题】:How to pin multiple SliverAppBars to the top from different scroll views如何从不同的滚动视图将多个 SliverAppBars 固定到顶部
【发布时间】:2021-10-08 18:31:52
【问题描述】:

在这种情况下,第一个 sliverAppBar 在滚动时正确固定到顶部。在 customScrollView 中有两个选项卡,它们有自己的滚动视图。在第一个选项卡内,是另一个 sliverAppBar,应该固定在第一个选项卡下。但是,它会滑到第一个 sliverAppBar 下方。现在既然我们的复杂视图不允许只用一个 customScrollView 来解决问题,有没有其他办法呢?

在此处查看图片(注意第一个 AppBar 如何与第二个 AppBar 重叠)

滚动前所需的效果

滚动后所需的效果

import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material App',
      home: Test(),
    );
  }
}
 
class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    final List<String> _tabs = ['Tab 1', 'Tab 2'];
    return DefaultTabController(
      length: _tabs.length,
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              SliverAppBar(
                title: const Text('1st App Bar'),
                pinned: true,
                forceElevated: innerBoxIsScrolled,
                bottom: TabBar(
                  tabs: _tabs.map((String name) => Tab(text: name)).toList(),
                ),
              ),
            ];
          },
          body: TabBarView(
            children: [
              CustomScrollView(
                slivers: [
                  SliverPadding(
                    padding: const EdgeInsets.all(8.0),
                    sliver: SliverFixedExtentList(
                      itemExtent: 48.0,
                      delegate: SliverChildBuilderDelegate(
                        (context, index) {
                          return ListTile(
                            title: Text('Item $index'),
                          );
                        },
                        childCount: 3,
                      ),
                    ),
                  ),
                  const SliverAppBar(
                    toolbarHeight: 150,
                    pinned: true,
                    backgroundColor: Colors.purple,
                    title: Text('2nd App Bar'),
                  ),
                  SliverPadding(
                    padding: const EdgeInsets.all(8.0),
                    sliver: SliverFixedExtentList(
                      itemExtent: 48.0,
                      delegate: SliverChildBuilderDelegate(
                        (BuildContext context, int index) {
                          return ListTile(
                            title: Text('Item $index'),
                          );
                        },
                        childCount: 20,
                      ),
                    ),
                  ),
                ],
              ),
              Placeholder(),
            ],
          ),
        ),
      ),
    );
  }
}

【问题讨论】:

  • 在第一个选项卡上会有另一个 AppBar,第二个选项卡只会使用第一个应用程序栏,对吗?
  • 在这种情况下,我认为会有滚动冲突,为了解决这个问题,我认为我们需要切换两个滚动控制器。
  • @YeasinSheikh 有什么想法或例子来说明如何做到这一点吗?
  • 我不确定是否要通过同一个控制器。否则我们必须检查子 ScrollController 偏移量是否为 0,然后启用父 ScrollController。并以这种方式在它们之间切换。
  • 您能否@YeasinSheikh 提供一个示例,不确定如何处理该建议?

标签: flutter flutter-layout


【解决方案1】:

我们可以使用Scaffold 持有第一个appBar。在tab 中,我们可以将第二个 appBar 设置为固定。如果您希望进行任何更改,请告诉我。

输出


class Test extends StatefulWidget {
  const Test({Key? key}) : super(key: key);

  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> with SingleTickerProviderStateMixin {
  static const List<Tab> myTabs = <Tab>[
    Tab(text: 'Tab1'),
    Tab(text: 'Tab2'),
  ];

  late TabController controller;

  @override
  void initState() {
    super.initState();
    controller = TabController(length: myTabs.length, vsync: this);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Appbar 1"),
        bottom: TabBar(
          controller: controller,
          tabs: myTabs,
        ),
      ),
      body: TabBarView(
        controller: controller,
        children: [
          CustomScrollView(
            slivers: [
              SliverAppBar(
                title: Text("AppBar 2"),
                pinned: true,
              ),
              SliverPadding(
                padding: const EdgeInsets.all(8.0),
                sliver: SliverFixedExtentList(
                  itemExtent: 48.0,
                  delegate: SliverChildBuilderDelegate(
                    (context, index) {
                      return ListTile(
                        title: Text('Item $index'),
                      );
                    },
                    childCount: 213,
                  ),
                ),
              ),
            ],
          ),
          Container(
            color: Colors.pink,
          ),
        ],
      ),
    );
  }
}

【讨论】:

  • 谢谢,这会起作用,但它会在像 slivers 一样扩展时减轻 sliverAppBar 的功能。
  • 关于第一个AppBar?
  • 对,第一个AppBar
  • 让我检查一下我是否也可以迁移那一个条子。
  • 谢谢,这就是我们陷入困境的地方.. :/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-16
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
相关资源
最近更新 更多