【问题标题】:Flutter TabBar Without AppBar没有 AppBar 的 Flutter TabBar
【发布时间】:2018-11-09 13:53:13
【问题描述】:

我正在尝试创建一个没有 AppBar 的选项卡式栏布局屏幕。我已经在此链接上提到了解决方案:how to create the tab bar without app bar in flutter? 但它对我不起作用。当我将 TabBar 放在 appbar: 参数中时,我的屏幕如下所示:

我的 TabBar 已移至状态栏下方的左上角,并且全部挤在一个角落。就好像它根本不存在一样。

当我使用 AppBar 类但只传递 bottom: 参数时,会发生以下情况:

TabBar 顶部有一个丑陋的空间,显然是为 AppBar 标题设计的。这是我的代码:

return new Scaffold(
      appBar: new TabBar(
        tabs: widget._tabs.map((_Page page){
          return Text(page.tabTitle);
        }).toList(),
        controller: _tabController,
        isScrollable: true,

      ),
      backgroundColor: Colors.white,
      body: new TabBarView(
          controller: _tabController,
          children: widget._tabs.map((_Page page){
            return new SafeArea(
                top:false,
                bottom: false,
                child: (page.page == Pages.cart?new CartHomeScreen():_lunchesLayout())
            );
          }).toList()
      ),
    );

我怎样才能让 TabBar 顶部没有那个空间?是否可以让两个选项卡项及其指示器拉伸并填充侧面空间?

【问题讨论】:

  • 你能发布预期的结果截图吗?

标签: dart flutter


【解决方案1】:

您的第一个屏幕截图实际上显示它运行良好 - 问题是“良好”并不是您所期望的。标签栏的默认文本颜色为白色,因此您的标签不会显示,而只是底线,这就是您在左上角看到的内容。此外,TabBar 已经是首选尺寸小部件,但它与 AppBar 的高度不同,因此如果您要这样做,它看起来不会像它。

这是一个使它看起来像应用栏的示例。 kToolbarHeight 与 AppBar 使用的常量相同。

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new MyAppState();
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'msc',
      home: new DefaultTabController(
        length: 2,
        child: new Scaffold(
          appBar: new PreferredSize(
            preferredSize: Size.fromHeight(kToolbarHeight),
            child: new Container(
              color: Colors.green,
              child: new SafeArea(
                child: Column(
                  children: <Widget>[
                    new Expanded(child: new Container()),
                    new TabBar(
                      tabs: [new Text("Lunches"), new Text("Cart")],
                    ),
                  ],
                ),
              ),
            ),
          ),
          body: new TabBarView(
            children: <Widget>[
              new Column(
                children: <Widget>[new Text("Lunches Page")],
              ),
              new Column(
                children: <Widget>[new Text("Cart Page")],
              )
            ],
          ),
        ),
      ),
    );
  }
}

结果如下:

编辑:

正如 cmets 和 this github issue 中所述,您还可以使用 AppBar 的 flexibleSpace 属性来保持标签栏的效果基本相同:

return new DefaultTabController(
  length: 3,
  child: new Scaffold(
    appBar: new AppBar(
      flexibleSpace: new Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          new TabBar(
            tabs: [
              new Tab(icon: new Icon(Icons.directions_car)),
              new Tab(icon: new Icon(Icons.directions_transit)),
              new Tab(icon: new Icon(Icons.directions_bike)),
            ],
          ),
        ],
      ),
    ),
  ),
);

【讨论】:

  • 你能解释一下给tabbar一些提升或阴影效果看起来像一个appbar吗?
  • @JayMungara 如果您查看the source code of appbar,您会发现他们使用Material 并设置了高程属性来显示阴影。你也可以这样做——用Material 替换容器并以相同的方式设置高度可能是最简单的。如果您对此有疑问,这似乎是一个新问题的候选者。
  • 这个答案很好,但我更喜欢使用flexibleSpace 而不是 appBar (我的用例)。看看github.com/flutter/flutter/issues/17459#issuecomment-387984398
  • @Touch 感谢您的建议,我已将其添加到答案中,因为 cmets 有时会迷路 =D
【解决方案2】:

按照下面的代码进行

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Container(
              height: MediaQuery.of(context).size.height / 2,
              child: Center(
                child: Text(
                  "Tabbar with out Appbar",
                  style: TextStyle(
                      color: Colors.white, fontWeight: FontWeight.bold),
                ),
              ),
              color: Colors.blue,
            ),
            TabBar(
              unselectedLabelColor: Colors.black,
              labelColor: Colors.red,
              tabs: [
                Tab(
                  text: '1st tab',
                ),
                Tab(
                  text: '2 nd tab',
                )
              ],
              controller: _tabController,
              indicatorSize: TabBarIndicatorSize.tab,
            ),
            Expanded(
              child: TabBarView(
                children: [
                  Container(child: Center(child: Text('people'))),
                  Text('Person')
                ],
                controller: _tabController,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

查看结果

【讨论】:

  • 这正是我所需要的。谢谢你。但记得处理掉tabController
  • 谢谢!这就是 TabBar 没有 Scaffold 的答案。
【解决方案3】:

我从 rmtmckenzie 获取代码,但只是为了创建一个没有材料应用程序的小部件

return new DefaultTabController(
      length: 3,
      child: new Scaffold(
        appBar: new PreferredSize(
          preferredSize: Size.fromHeight(kToolbarHeight),
          child: new Container(
            height: 50.0,
            child: new TabBar(
              tabs: [
                Tab(icon: Icon(Icons.directions_car,color: Colors.grey,)),
                Tab(icon: Icon(Icons.directions_transit,color: Colors.grey)),
                Tab(icon: Icon(Icons.directions_bike,color: Colors.grey)),
              ],
            ),
          ),
        ),
        body: TabBarView(
          children: [
            Icon(Icons.directions_car),
            Icon(Icons.directions_transit),
            Icon(Icons.directions_bike),
          ],
        ),
      ),
    ); 

【讨论】:

  • 我得到“底部溢出 2 个像素”
  • 没有scaffold()有没有办法使用tabbar?
【解决方案4】:

您不需要使用appBar 属性:

Scaffold(
  body: Column(
    children: [
      TabBar( // <-- Your TabBar
        tabs: [
          Tab(icon: Icon(Icons.camera)),
          Tab(icon: Icon(Icons.settings)),
        ],
      ),
      Expanded(
        child: TabBarView( // <-- Your TabBarView
          children: [
            Container(color: Colors.blue),
            Container(color: Colors.red),
          ],
        ),
      ),
    ],
  ),
)

【讨论】:

    【解决方案5】:

    只使用flexiblespace 道具而不是appBar 的底部道具。 全部在 safeArea 小部件中,您可以添加一些垂直填充。

    home: SafeArea(
            top: true,
            child: Padding(
              padding: const EdgeInsets.only(top: 10.0),
              child: DefaultTabController(
                length: 3,
                child: Scaffold(
                  appBar: AppBar(
                    flexibleSpace: TabBar(
                      tabs: [
                        Tab(icon: Icon(Icons.1)),
                        Tab(icon: Icon(Icons.2)),
                        Tab(icon: Icon(Icons.3)),
                      ],
                    ),
                  ),
                  body: TabBarView(
                    children: [
                      Icon(Icons.1),
                      Icon(Icons.2),
                      Icon(Icons.3),
                    ],
                  ),
                ),
              ),
            ),
          )
    

    【讨论】:

      【解决方案6】:

      只需在AppBar 小部件中使用toolbarHeight 属性和kMinInteractiveDimension 值,如下所示:

      Scaffold(
        appBar: AppBar(
          toolbarHeight: kMinInteractiveDimension,
          bottom: TabBar(
            controller: _tabController,
            tabs: [], // your tab bars
          ),
        ),
        body: TabBarView(
          controller: _tabController,
          children: [], // your tab views
        ),
      );
      

      【讨论】:

        【解决方案7】:

        appBar属性中直接使用TabBar

        @override
        Widget build(BuildContext context) {
          return DefaultTabController(
            length: 2,
            child: Scaffold(
              appBar: TabBar(
                tabs: [
                  Tab(icon: Icon(Icons.call)),
                  Tab(icon: Icon(Icons.message)),
                ],
              ),
              body: TabBarView(
                children: [
                  Center(child: Text('Call')),
                  Center(child: Text('Message')),
                ],
              ),
            ),
          );
        }
        

        【讨论】:

        • 非常感谢,这非常有效。而且很简单
        【解决方案8】:

        很简单,您只需提供height 到您的TabView

        这是一个简单的例子。您可以使用DefaultTabControllerTabController。为了完全可定制,我将使用TabController

        _getTabBar函数返回选项卡列表。

          TabBar _getTabBar() {
            return TabBar(
              tabs: <Widget>[
                Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
                Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
              ],
              controller: tabController,
            );
          }
        

        _getTabBarView 将小部件列表作为输入参数并创建一个选项卡视图。

          TabBarView _getTabBarView(tabs) {
            return TabBarView(
              children: tabs,
              controller: tabController,
            );
          }
        

        SafeArea 用于将内容移动到状态栏下方。 _getTabBarViewContainer 包裹,这样我们就可以分配一个高度。这是分配高度的一种方式,您也可以使用其他方式。

        这里是完整的代码,包裹在MaterialApp 中,你就有了一个完全可定制的标签栏和视图。生命周期方法用于创建和处置TabController

        import 'package:flutter/material.dart';
        
        class TabControllerScreen extends StatefulWidget {
        
          @override
          _TabControllerScreenState createState() => _TabControllerScreenState();
        }
        
        class _TabControllerScreenState extends State<TabControllerScreen> with SingleTickerProviderStateMixin {
          TabController tabController;
        
          @override
          void initState() {
            super.initState();
            tabController = TabController(length: 2, vsync: this);
          }
        
          @override
          void dispose() {
            tabController.dispose();
            super.dispose();
          }
        
          TabBar _getTabBar() {
            return TabBar(
              tabs: <Widget>[
                Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
                Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
              ],
              controller: tabController,
            );
          }
        
          TabBarView _getTabBarView(tabs) {
            return TabBarView(
              children: tabs,
              controller: tabController,
            );
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              body: SafeArea(
                child: Column(
                  children: <Widget>[
                    _getTabBar(),
                    Container(
                      height: 100,
                      child: _getTabBarView(
                        <Widget>[
                          Icon(Icons.home),
                          Icon(Icons.settings),
                        ],
                      ),
                    )
                  ],
                ),
              ),
            );
          }
        }
        
        

        【讨论】:

          【解决方案9】:

          根据 CopsOnRoad 的回答,我创建了一个隐藏的 TabBar,如下所示:

          Scaffold(
            body: Column(
              children: [
                TabBar( // <-- Hidden TabBar
                  indicator: BoxDecoration(),
                  tabs: [
                    SizedBox.shrink(),
                    SizedBox.shrink(),
                  ],
                ),
                Expanded(
                  child: TabBarView( // <-- Your TabBarView
                    children: [
                      Container(color: Colors.blue),
                      Container(color: Colors.red),
                    ],
                  ),
                ),
              ],
            ),
          )
          

          【讨论】:

            【解决方案10】:

            尝试将TabBar 放入AppBarflexibleSpace 属性中。

            【讨论】:

              猜你喜欢
              • 2021-09-10
              • 2020-03-01
              • 2020-09-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-11-11
              相关资源
              最近更新 更多