将TabBar像SliverAppBar一样隐藏

最白目*_*最白目 7 dart flutter

因此,网络上有很多示例,您可以SliverAppBar在滚动条上使用隐藏的内容,并且TabBar仍在下面显示。我找不到反过来做的任何事情:当我向上滚动时,我只想隐藏TabBarAppBar始终保持持续显示。有谁知道如何实现这一目标?

这是一个隐藏AppBar的示例(这不是我想要的,只是有助于更好地了解我想要的东西)。

更新

到目前为止,这是我尝试过的,并且我认为它可以工作,但是问题是我无法AppBarPositioned野外获得正确的高度(例如,iPhone X的高度更大并且与标签栏重叠)。

// this sliver app bar is only use to hide/show the tabBar, the AppBar  
// is invisible at all times. The to the user visible AppBar is below
return Scaffold(
  body: Stack(
    children: <Widget>[
      NestedScrollView(
        headerSliverBuilder:
            (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              floating: true,
              snap: true,
              pinned: false,
              bottom: TabBar(
                tabs: [
                  Tab(
                    child: Text(
                      "1",
                      textAlign: TextAlign.center,
                    ),
                  ),
                  Tab(
                    child: Text(
                      "2",
                      textAlign: TextAlign.center,
                    ),
                  ),
                  Tab(
                    child: Text(
                      "3",
                      textAlign: TextAlign.center,
                    ),
                  ),
                ],
                controller: _tabController,
              ),
            ),
          ];
        },
        body: TabBarView(
          children: [
            MyScreen1(),
            MyScreen2(),
            MyScreen3(),
          ],
          controller: _tabController,
          physics: new NeverScrollableScrollPhysics(),
        ),
      ),


      // Here is the AppBar the user actually sees. The SliverAppBar 
      // above will slide the TabBar underneath this one. However,
      // I can´t figure out how to give it the correct height.
      Container(
        child: Positioned(
          top: 0.0,
          left: 0.0,
          right: 0.0,
          child: AppBar(
            iconTheme: IconThemeData(
              color: Colors.red, //change your color here
            ),
            automaticallyImplyLeading: true,
            elevation: 0,
            title: Text("My Title"),
            centerTitle: true,

          ),
        ),
      ),

    ],

  ),
);
Run Code Online (Sandbox Code Playgroud)

Sae*_*bil 7

是如何做到这一点的,想法是postframecallback在 a 的帮助下使用 aGlobalKey来预先计算appBar height并添加exapandedHeight如下所示的,

\n\n
import \'package:flutter/material.dart\';\nimport \'package:flutter/scheduler.dart\';\n\nvoid main() => runApp(MyApp());\n\nclass MyApp extends StatelessWidget {\n  // This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: \'Flutter Demo\',\n      theme: ThemeData(\n\n        primarySwatch: Colors.blue,\n      ),\n      home: MyHomePage(title: \'Flutter Demo Home Page\'),\n    );\n  }\n}\n\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin  {\n\n  TabController _tabController;\n  GlobalKey _appBarKey;\n  double _appBarHight;\n  @override\n  void initState() {\n    _appBarKey = GlobalKey();\n    _tabController = TabController(length: 3, vsync: this);\n    SchedulerBinding.instance.addPostFrameCallback(_calculateAppBarHeight);\n    super.initState();\n  }\n  _calculateAppBarHeight(_){\n    final RenderBox renderBoxRed = _appBarKey.currentContext.findRenderObject();\n     setState(() {\n  _appBarHight = renderBoxRed.size.height;\n});\n    print("AppbarHieght = $_appBarHight");\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    // this sliver app bar is only use to hide/show the tabBar, the AppBar\n    // is invisible at all times. The to the user visible AppBar is below\n    return Scaffold(\n      body: Stack(\n        children: <Widget>[\n          NestedScrollView(\n            headerSliverBuilder:\n                (BuildContext context, bool innerBoxIsScrolled) {\n              return <Widget>[\n                SliverAppBar(\n                  floating: true,\n                  expandedHeight: _appBarHight,\n                  snap: true,\n                  pinned: false,\n                  bottom: TabBar(\n                    tabs: [\n                      Tab(\n                        child: Text(\n                          "1",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                      Tab(\n                        child: Text(\n                          "2",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                      Tab(\n                        child: Text(\n                          "3",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                    ],\n                    controller: _tabController,\n                  ),\n                ),\n              ];\n            },\n            body: TabBarView(\n              children: [\n                MyScreen1(),\n                MyScreen2(),\n                MyScreen3(),\n              ],\n              controller: _tabController,\n              physics: new NeverScrollableScrollPhysics(),\n            ),\n          ),\n\n\n          // Here is the AppBar the user actually sees. The SliverAppBar\n          // above will slide the TabBar underneath this one. However,\n          // I can\xc2\xa5t figure out how to give it the correct height.\n          Container(\n            key: _appBarKey,\n            child: Positioned(\n              top: 0.0,\n              left: 0.0,\n              right: 0.0,\n              child: AppBar(\n\n                backgroundColor: Colors.red,\n                iconTheme: IconThemeData(\n                  color: Colors.red, //change your color here\n                ),\n                automaticallyImplyLeading: true,\n                elevation: 0,\n                title: Text("My Title"),\n                centerTitle: true,\n\n              ),\n            ),\n          ),\n\n        ],\n\n      ),\n    );\n  }\n\n}\n\nclass MyScreen1 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Center(\n        child: Text("My Screen 1"),\n      ),\n    );\n  }\n}\nclass MyScreen2 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Center(\n        child: Text("My Screen 2"),\n      ),\n    );\n  }\n}\nclass MyScreen3 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Center(\n        child: Text("My Screen 3"),\n      ),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑:

\n\n

经过更多调查后,我通过仅使用SafeAreaWidget 找到了一个没有键或 MediaQuery“东西”的解决方案。请检查以下完整代码:

\n\n
import \'package:flutter/material.dart\';\n\nvoid main() => runApp(MyApp());\n\nclass MyApp extends StatelessWidget {\n  // This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: \'Flutter Demo\',\n      theme: ThemeData(\n\n        primarySwatch: Colors.blue,\n      ),\n      home: MyHomePage(title: \'Flutter Demo Home Page\'),\n    );\n  }\n}\n\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin  {\n\n  TabController _tabController;\n\n  @override\n  void initState() {\n\n    _tabController = TabController(length: 3, vsync: this);\n\n    super.initState();\n  }\n\n\n  @override\n  Widget build(BuildContext context) {\n    // this sliver app bar is only use to hide/show the tabBar, the AppBar\n    // is invisible at all times. The to the user visible AppBar is below\n    return Scaffold(\n      body: Stack(\n        children: <Widget>[\n          NestedScrollView(\n\n            headerSliverBuilder:\n                (BuildContext context, bool innerBoxIsScrolled) {\n              return <Widget>[\n                SliverAppBar(\n                  primary: true,\n                  floating: true,\n                  backgroundColor: Colors.blue,//.withOpacity(0.3),\n                  snap: true,\n                  pinned: false,\n                  bottom: TabBar(\n                    tabs: [\n                      Tab(\n                        child: Text(\n                          "1",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                      Tab(\n                        child: Text(\n                          "2",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                      Tab(\n                        child: Text(\n                          "3",\n                          textAlign: TextAlign.center,\n                        ),\n                      ),\n                    ],\n                    controller: _tabController,\n                  ),\n                ),\n              ];\n            },\n            body: TabBarView(\n              children: [\n                MyScreen1(),\n                MyScreen2(),\n                MyScreen3(),\n              ],\n              controller: _tabController,\n              physics: new NeverScrollableScrollPhysics(),\n            ),\n          ),\n\n\n          // Here is the AppBar the user actually sees. The SliverAppBar\n          // above will slide the TabBar underneath this one. \n          // by using SafeArea it will.\n          Positioned(\n            top: 0.0,\n            left: 0.0,\n            right: 0.0,\n            child: Container(\n              child: SafeArea(\n                top: false,\n                child: AppBar(\n                  backgroundColor: Colors.blue,\n//                iconTheme: IconThemeData(\n//                  color: Colors.red, //change your color here\n//                ),\n                  automaticallyImplyLeading: true,\n                  elevation: 0,\n                  title: Text("My Title",),\n                  centerTitle: true,\n                ),\n              ),\n            ),\n          ),\n\n        ],\n\n      ),\n    );\n  }\n\n}\n\nclass MyScreen1 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      color: Colors.yellow,\n      child: Center(\n        child: Text("My Screen 1"),\n      ),\n    );\n  }\n}\nclass MyScreen2 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Center(\n        child: Text("My Screen 2"),\n      ),\n    );\n  }\n}\nclass MyScreen3 extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      child: Center(\n        child: Text("My Screen 3"),\n      ),\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n