【问题标题】:How to create a bounded scrollable TabBarView如何创建有界可滚动的 TabBarView
【发布时间】:2019-05-13 19:14:28
【问题描述】:

我需要在 Flutter 中实现如下布局。

当用户滚动时,我希望整个布局滚动(隐藏标题和标签栏)。但是,我不能将 TabBarView 嵌套在 ListView 中,因为 TabBarView 没有限定高度,而且 ListView 也不为其子级提供限定高度。

我已经看到了这些问题,但是对于这个用例,他们都有不满意的答案:

【问题讨论】:

    标签: flutter widget flutter-layout flutter-sliver


    【解决方案1】:

    class SliverWithTabBar extends StatefulWidget {
      @override
      _SliverWithTabBarState createState() => _SliverWithTabBarState();
    }
    
    class _SliverWithTabBarState extends State<SliverWithTabBar> with SingleTickerProviderStateMixin {
      TabController controller;
    
      @override
      void initState() {
        super.initState();
        controller = TabController(length: 3, vsync: this);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: NestedScrollView(
            headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
              return [
                SliverAppBar(
                  pinned: false,
                  backgroundColor: Colors.white,
                  flexibleSpace: FlexibleSpaceBar(
                    collapseMode: CollapseMode.pin,
                    background: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Container(
                          height: 200.0,
                          width: double.infinity,
                          color: Colors.grey,
                          child: FlutterLogo(),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(10.0),
                          child: Text(
                            'Business Office',
                            style: TextStyle(fontSize: 25.0),
                            textAlign: TextAlign.left,
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(10.0),
                          child: Text(
                            'Open now\nStreet Address, 299\nCity, State',
                            style: TextStyle(fontSize: 15.0),
                            textAlign: TextAlign.left,
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(right: 10.0),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: <Widget>[
                              Icon(Icons.share),
                              Padding(
                                padding: const EdgeInsets.only(left: 10.0),
                                child: Icon(Icons.favorite),
                              ),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                  expandedHeight: 380.0,
                  bottom: TabBar(
                    indicatorColor: Colors.black,
                    labelColor: Colors.black,
                    tabs: [
                      Tab(text: 'POSTS'),
                      Tab(text: 'DETAILS'),
                      Tab(text: 'FOLLOWERS'),
                    ],
                    controller: controller,
                  ),
                )
              ];
            },
            body: ListView.builder(
              itemCount: 100,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                  color: index % 2 == 0 ? Colors.blue : Colors.green,
                  child: Container(
                    alignment: Alignment.center,
                    width: double.infinity,
                    height: 100.0,
                    child: Text(
                      'Flutter is awesome',
                      style: TextStyle(fontSize: 18.0),
                    ),
                  ),
                );
              },
            ),
          ),
        );
      }
    }
    

    您应该寻找Sliver 小部件来实现NestedScrollView

    这为您提供了一个 headerSliv​​erBuilder 属性,您可以在其中实际放置一些标题,当正文小部件滚动时,您可能会隐藏或固定在屏幕顶部,在此特定示例中,@987654327 @。

    您可能需要查看RenderSliver 文档。

    【讨论】:

    • 非常感谢,这非常有效!我发现有点难以将我的头包裹在条子上,但你的例子让我更清楚。我希望文档有这样的例子!
    • 谢谢兄弟。但我不能做滚动标签?我设置了 isScrollable: true
    • 如何从左向右滑动小部件,反之亦然?
    • 为了让 TabBar 的 Tabs 完美运行,...在 NestedScrollView 的主体中使用 TabBarView ....
    • 这实际上是不对的IMO!您已经在 NestedScrollView 的主体中放置了一个 ListView。在您拥有 TabBarView 之前,标题部分中的 TabBar 是无用的。但是:如果你把 TabBarView 作为 body -> 你会遇到这些问题: TabBarView 需要一个有界的高度! (它不会自动占用剩余空间,您甚至不能使用 Extended 小部件来扩展列中的高度)。每个 Tab 内容都有不同的长度(高度),因此您甚至无法选择特定的高度。
    【解决方案2】:

    在 Miguel Ruvio 的回答之上,将正文中的 ListView 替换为 TabBarView 几乎可以让您按照 D.R. 的评论进行操作。当我在其中的一个小部件被包装在一列中时,我确实遇到了一些溢出问题。根据这个用 ListView 替换它 example

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(home: Tabs()));
    }
    
    class Tabs extends StatefulWidget {
      @override
      _RoomTabsState createState() => _RoomTabsState();
    }
    
    class _RoomTabsState extends State<Tabs> with TickerProviderStateMixin {
      var _scrollViewController;
      var _tabController;
    
      @override
      void initState() {
        super.initState();
        _scrollViewController = ScrollController();
        _tabController = TabController(vsync: this, length: 2);
      }
    
      @override
      Widget build(BuildContext context) {
        return NestedScrollView(
          controller: _scrollViewController,
          headerSliverBuilder: (context, bool) => [
            SliverAppBar(
              bottom: TabBar(
                controller: _tabController,
                tabs: [
                  Tab(text: "All"),
                  Tab(text: "Living room"),
                ],
              ),
            ),
          ],
          body: TabBarView(
            controller: _tabController,
            children: [
              ListView(children: [
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
                Text("test"),
              ]),
              Text("test"),
            ],
          ),
        );
      }
    }
    
    

    来自github issue

    【讨论】:

      【解决方案3】:

      请尝试以下代码:

       NestedScrollView(
        headerSliverBuilder: (context, value) {
          return [
            SliverToBoxAdapter(
                child: Header()
            ),
            SliverToBoxAdapter(
              child: TabBar(
                controller: _controller,
                tabs: [
                  Tab(icon: Icon(Icons.x)),
                  Tab(icon: Icon(Icons.y)),
                  Tab(icon: Icon(Icons.z)),
                ],
              ),
            ),
          ];
        },
      body: Container(
        child: TabBarView(
          controller: _controller,
          children: <Widget>[
            page1(),
            page2(),
            page3(),
          ],
        ),
      ),
      

      )

      【讨论】:

        猜你喜欢
        • 2023-01-23
        • 2020-02-02
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 2020-01-21
        • 1970-01-01
        • 2021-05-30
        • 1970-01-01
        相关资源
        最近更新 更多