带有选项卡的SliverAppBar

16

如何在Flutter中将TabBar添加到SliverAppBar?到目前为止,当我在SliverAppBar中添加bottom时,title会固定在那些选项卡上方,而我希望它位于这些选项卡之上。
有什么想法吗?

屏幕

我的代码:

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
  TabController controller;


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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new CustomScrollView(
        slivers: <Widget>[
          new SliverAppBar(
            pinned: true,
            flexibleSpace: new FlexibleSpaceBar(
              title: new Text("Some title"),
            ),
            expandedHeight: 160.0,
            bottom: new TabBar(tabs: [
              new Tab(text: 'Tab 1'),
              new Tab(text: 'Tab 2'),
              new Tab(text: 'Tab 3'),
            ],
            controller: controller,
            ),
          ),
          new SliverList(
            delegate: new SliverChildBuilderDelegate(
              (context, idx) {
                return new ListTile(
                  title: new Text("$idx"),
                );
              },
              childCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}

有运气吗? 我遇到了同样的问题。 - Evgeny Vasilyev
同样的问题在这里 :( - diegoveloper
我认为这是一个未解决的问题。 https://github.com/flutter/flutter/issues/25723 - jwehrle
5个回答

57

几周前我也遇到了同样的问题,我使用了SliverAppBarFlexibleSpaceBarSliverPersistentHeader解决了这个问题。

检查我的代码

  @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: DefaultTabController(
          length: 2,
          child: NestedScrollView(
            headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget>[
                SliverAppBar(
                  expandedHeight: 200.0,
                  floating: false,
                  pinned: true,
                  flexibleSpace: FlexibleSpaceBar(
                      centerTitle: true,
                      title: Text("Collapsing Toolbar",
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 16.0,
                          )),
                      background: Image.network(
                        "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&h=350",
                        fit: BoxFit.cover,
                      )),
                ),
                SliverPersistentHeader(
                  delegate: _SliverAppBarDelegate(
                    TabBar(
                      labelColor: Colors.black87,
                      unselectedLabelColor: Colors.grey,
                      tabs: [
                        Tab(icon: Icon(Icons.info), text: "Tab 1"),
                        Tab(icon: Icon(Icons.lightbulb_outline), text: "Tab 2"),
                      ],
                    ),
                  ),
                  pinned: true,
                ),
              ];
            },
            body: Center(
              child: Text("Sample text"),
            ),
          ),
        ),
      );
    }

这是SliverPersistentHeader的实现

  class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
    _SliverAppBarDelegate(this._tabBar);

    final TabBar _tabBar;

    @override
    double get minExtent => _tabBar.preferredSize.height;
    @override
    double get maxExtent => _tabBar.preferredSize.height;

    @override
    Widget build(
        BuildContext context, double shrinkOffset, bool overlapsContent) {
      return new Container(
        child: _tabBar,
      );
    }

    @override
    bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
      return false;
    }
  }

如果您想查看,我写了一篇关于此的文章:

https://medium.com/@diegoveloper/flutter-collapsing-toolbar-sliver-app-bar-14b858e87abe


尊重!谢谢! - Marcin Szałek
当我们在选项卡中嵌套列表视图时,布局会崩溃。请帮忙解决。 - Shyju M
请见以下代码链接:https://gist.githubusercontent.com/shyjuzz/9cac508be0b6226ac7561f679b17d872/raw/626c395b75d33267eebae6e669f7b17f7ed2813f/sliverlisttab.dart - Shyju M
2
在这个实现中,选项卡栏位于标题栏之后,如何使选项卡栏具有透明背景并覆盖底部AppBar图片? - fvisticot
2
TabView在TabBar后面了,如何让它拉伸? - akshay bhange
2
@diegoveloper,TabBarView在TabBar后面重叠了,你知道如何解决吗?谢谢。 - HeIsDying

4

如果您将其放置在SilverAppBar:title中,标题将不会展开。 - Marcin Szałek

1
class Menu extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: SafeArea(
        child: Scaffold(
          body: Consumer<MenuBlock>(
              builder: (context, appController, child) {
            return CustomScrollView(
              slivers: <Widget>[
                SliverAppBar(
                  floating: true,
                  pinned: false,
                  snap: true,
                  forceElevated: true,
                  elevation: 1,
                  expandedHeight: 50.0,
                  title: Text('TITLE'),
                  actions: <Widget>[
                    IconButton(
                      icon: const Icon(Icons.add_circle),
                      tooltip: 'Add new entry',
                      onPressed: () {/* ... */},
                    ),
                  ],
                  bottom: TabBar(
                    tabs: [
                      Tab(text: "TAB1"),
                      Tab(text: "TAB2"),
                    ],
                  ),
                ),
                SliverList(
                  delegate: SliverChildListDelegate(
                    <Widget>[
                      Container(
                        // or SizedBox, etc.
                        height: 4200,
                        child: TabBarView(
                          children: [
                     
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            );
          }),
        ),
      ),
    );
  }
}

1
虽然这可能回答了问题,但你应该[编辑]你的答案,以包括一个解释如何这个代码块回答了问题。这有助于提供上下文,并使你的答案对那些可能在以后遇到相同问题的人更有用。 - Hoppeduppeanut
这并没有解决将视图隐藏在选项卡视图后面的问题。 - PRATHIV

1
您可以使用 titlePadding 来设置填充:
              SliverAppBar(
                  pinned: true,
                  expandedHeight: 250,
                  primary: true,
                  forceElevated: true,
                  flexibleSpace: FlexibleSpaceBar(
                    titlePadding: EdgeInsets.only(bottom: 62),
                    title: Text(data.name),
                    centerTitle: true,
                    background: data.logo != null
                        ? Padding(
                            padding: const EdgeInsets.only(bottom: 46),
                            child: Container(
                              color: Colors.black,
                            ),
                          )
                        : null,
                  ),
                  bottom: TabBar(
                    tabs: [
                      Tab(text: "Tab1"),
                      Tab(text: "Tab2"),
                      Tab(text: "Tab3"),
                      Tab(text: "Tab4"),
                    ],
                  ),
                ),

-1

这对我非常有效。我认为这可能会对你有所帮助。

NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [
          SliverAppBar(
            backgroundColor: AppColors.appbarColor,
            snap: false,
            pinned: true,
            floating: true, //this make the work done.
            title: const Text(
              'WhatsApp',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.w500,
                color: Colors.white,
              ),
            ),
            actions: const [
              IconButton(
                onPressed: null,
                icon: Icon(
                  Icons.search_outlined,
                  color: Colors.white,
                  size: 24,
                ),
              ),
              IconButton(
                onPressed: null,
                icon: Icon(
                  Icons.more_vert,
                  color: Colors.white,
                  size: 24,
                ),
              ),
            ],
            bottom: TabBar(
              controller: _tabController,
            
              indicatorColor: Colors.white,
              indicatorWeight: 3.0,
              
              tabs: TabBarItem.tabList.map((tab) => tab).toList(),
            ),
          ),
        ],
        body: TabBarView(
          controller: _tabController,
          children: const [
            Text('camera'),
            ChatsScreen(),
            Text('camera'),
            Text('camera'),
          ],
        ),
      ),

这并没有解决在选项卡视图后面隐藏视图的问题。 - PRATHIV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接