Flutter Web - 如何在 SingleChildScrollView -> Column 中使用 TabBarView?

Flutter Web - How to use a TabBarView inside a SingleChildScrollView -> Column?

我有一个带有 Column 的 SingleChildScrollView 作为子级,有很多子级,其中两个是 TabBar 和 TabBarView。 TabBar 呈现正常,但是当我添加 TabBarView 时出现错误:

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performResize():
Horizontal viewport was given unbounded height.

Viewports expand in the cross axis to fill their container and constrain their children to match their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of vertical space in which to expand.
The relevant error-causing widget was: 
  TabBarView file:///C:/Users/user/Documents/FlutterProjects/singlechildscrollview/lib/main.dart:83:13
When the exception was thrown, this was the stack: 
#0      RenderViewport.computeDryLayout.<anonymous closure> (package:flutter/src/rendering/viewport.dart:1418:15)
#1      RenderViewport.computeDryLayout (package:flutter/src/rendering/viewport.dart:1430:6)
#2      RenderBox.performResize (package:flutter/src/rendering/box.dart:2332:12)
#3      RenderObject.layout (package:flutter/src/rendering/object.dart:1758:9)
#4      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:116:14)
...
The following RenderObject was being processed when the exception was fired: RenderViewport#4db57 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...  needs compositing
...  parentData: <none> (can use size)
...  constraints: BoxConstraints(0.0<=w<=568.0, 0.0<=h<=Infinity)
...  size: MISSING
...  axisDirection: right
...  crossAxisDirection: down
...  offset: _PagePosition#05511(range: null..null, viewport: null, ScrollableState, _ForceImplicitScrollPhysics -> PageScrollPhysics -> PageScrollPhysics -> ClampingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#083c3, ScrollDirection.idle)
...  anchor: 0.0
RenderObject: RenderViewport#4db57 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
  needs compositing
  parentData: <none> (can use size)
  constraints: BoxConstraints(0.0<=w<=568.0, 0.0<=h<=Infinity)
  size: MISSING
  axisDirection: right
  crossAxisDirection: down
  offset: _PagePosition#05511(range: null..null, viewport: null, ScrollableState, _ForceImplicitScrollPhysics -> PageScrollPhysics -> PageScrollPhysics -> ClampingScrollPhysics -> ClampingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#083c3, ScrollDirection.idle)
  anchor: 0.0
...  center child: _RenderSliverFractionalPadding#c51bd NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
...    parentData: paintOffset=Offset(0.0, 0.0)
...    constraints: MISSING
...    geometry: null
...    child: RenderSliverFillViewport#29be2 NEEDS-LAYOUT NEEDS-PAINT
...      parentData: paintOffset=Offset(0.0, 0.0)
...      constraints: MISSING
...      geometry: null
...      no children current live
====================================================================================================

======== Exception caught by rendering library =====================================================
The following assertion was thrown during performLayout():
RenderBox was not laid out: RenderViewport#4db57 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1930 pos 12: 'hasSize'

我知道这个错误与 TabBarView 没有高度有关,我无法设置特定高度,因为每个选项卡的内容都是动态的或使用任何其他 ScrollView,我已经尝试将其包装到a Flexible with fit: FlexFit.loose 并设置为所有 Column 的 mainAxisSize: MainAxisSize.min 但它仍然不起作用。

class MyHomePage extends StatefulWidget {

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

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin{

  late TabController tabController;

  @override
  void initState() {

    super.initState();
    tabController = TabController(length: 2, vsync: this);
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: [
            
            /// Other widgets here...then

            TabBar(
              controller: tabController,
              tabs: [

                Tab(
                  child: Text(
                      "Tab 1",
                      style: TextStyle(
                        color: Colors.black
                      ),
                  ),
                ),

                Tab(
                  child: Text(
                    "Tab 1",
                    style: TextStyle(
                        color: Colors.black
                    ),
                  ),
                ),


              ],
            ),

            TabBarView(
              controller: tabController,
              children: [

                /// Each content from each tab will have a dynamic height
                Container(),
                Container()

              ],
            )


          ],
        ),
      ),

    );
  }
}

您可以使用此示例应用作为示例。简而言之,我将 TabBarTabBarView 嵌套在 NestedScrollView 中,以占据屏幕的全尺寸。这样你就可以在 TabBarView

中有一个动态的 body
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: MyHomePage()));
}

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

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late TabController tabController;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: NestedScrollView(
        headerSliverBuilder: (context, value) {
          return [
            SliverToBoxAdapter(
              child: TabBar(
                controller: tabController,
                labelColor: Colors.redAccent,
                isScrollable: true,
                tabs: [
                  Tab(
                    child: Text(
                      "Tab 1",
                      style: TextStyle(color: Colors.black),
                    ),
                  ),
                  Tab(
                    child: Text(
                      "Tab 1",
                      style: TextStyle(color: Colors.black),
                    ),
                  ),
                ],
              ),
            ),
          ];
        },
        body: Container(
          child: TabBarView(
            controller: tabController,
            children: [
              /// Each content from each tab will have a dynamic height
              Container(),
              Container()
            ],
          ),
        ),
      ),
    );
  }
}