简体   繁体   English

Flutter:SingleChildScrollView 内的 TabBarView

[英]Flutter: TabBarView inside SingleChildScrollView

My problem is that I want a TabBarView inside a SingleChildScrollView but it gives me this error: RenderFlex children have non-zero flex but incoming height constraints are unbounded.我的问题是我想要一个 TabBarView 在 SingleChildScrollView 中,但它给了我这个错误: RenderFlex children have non-zero flex 但传入的高度约束是无限的。

If I remove the SingleChildScrollView it works but I need the widget because then I want to push a ListView that it scrolls with the TabBar , like Instagram.如果我删除SingleChildScrollView它可以工作,但我需要小部件,因为那时我想推送一个 ListView ,它与TabBar一起滚动,比如 Instagram。

Code:代码:

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  TabController tabController;

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: SingleChildScrollView(
      child: Column(
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.photo_library,
                  size: 30,
                ),
              ),
              Tab(
                icon: Icon(
                  Icons.perm_media,
                  size: 30,
                ),
              ),
            ],
            labelColor: Colors.deepOrange,
            unselectedLabelColor: Colors.black,
            indicatorColor: Colors.deepOrange,
          ),
          Expanded(
            child: TabBarView(controller: tabController, children: [
              Expanded(child: Container()),
              Expanded(child: Container())
            ]),
          ),
        ],
      ),
    )));
  }
}

Changes:变化:

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  TabController tabController;

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.photo_library,
                  size: 30,
                ),
              ),
              Tab(
                icon: Icon(
                  Icons.perm_media,
                  size: 30,
                ),
              ),
            ],
            labelColor: Colors.deepOrange,
            unselectedLabelColor: Colors.black,
            indicatorColor: Colors.deepOrange,
          ),
          Expanded(
            child: SingleChildScrollView(child:TabBarView(controller: tabController, children: [
              Container(),
              Container()
            ]),
          ),)
        ],
      ),
    ));
  }
}

You can use NestedScrollView to fix this issue.您可以使用NestedScrollView来解决此问题。

The below code helped me to solve:下面的代码帮助我解决了:

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(),
        ],
      ),
    ),
  )

For further explanation, refer to this answer如需进一步解释,请参阅此答案

The TabBarView requires a finite height which the SingleChildScrollView cant offer. TabBarView 需要 SingleChildScrollView 无法提供的有限高度。 The Problem is you are using expanded in a column that is inside a SingleChildScrollView.问题是您在 SingleChildScrollView 内的列中使用扩展。


This answer from a similar question might help you This answer from a similar question可能会对您有所帮助

The answer is in the error itself.答案就在错误本身。 When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded as a child of the column it is working opposite to the column trying to shrink-wrap its children.当列在可滚动的视图内时,该列正在尝试收缩包装其内容,但由于您使用 Expanded 作为该列的子级,它的工作方式与尝试收缩其子级的列相反。 Both are trying to achieve an exactly opposite task.两者都试图完成一个完全相反的任务。 Og OG

This is causing this error because these two directives are completely opposite to each other.这是导致此错误的原因,因为这两个指令彼此完全相反。 As mentioned in the error logs try the following: Consider setting mainAxisSize to MainAxisSize.min (for column) and using FlexFit.loose fits for the flexible (use Flexible rather than Expanded).如错误日志中所述,请尝试以下操作:考虑将mainAxisSize设置为MainAxisSize.min (用于列)并使用FlexFit.loose进行灵活拟合(使用 Flexible 而不是 Expanded)。

I ran into similar issue.我遇到了类似的问题。 My Solution was to Use a Container instead of a TabBarView to show the children(tabs).我的解决方案是使用容器而不是 TabBarView 来显示子项(选项卡)。

You can switch the content of this container based on the index selected By TabBar.您可以根据通过 TabBar 选择的索引来切换此容器的内容。

Of course if you need swipe gesture to move between tabs you need to add that as well for me it was not needed.当然,如果您需要滑动手势在选项卡之间移动,您也需要添加它,对我来说这不是必需的。 Code looks Something like this.代码看起来像这样。

import 'package:flutter/material.dart';

class Screen extends StatefulWidget {
  Screen({
    Key key,
  }) : super(key: key);

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

class _ScreenState extends State<Screen> with TickerProviderStateMixin {
  TabController _builderPageController;
  List<Widget> _tabs;
  List<Tab> _tabItems;
  int selectedtabIndex = 0;

  @override
  void initState() {
    super.initState();
    _initTabController();
    _setUpTabComponents();
    _preprareTabItems();
  }

  Column _showWidgets() {
    return Column(
      children: [
        Container(
          // your non tab widgets goes here
          height: 300,
          color: Colors.blueAccent,
        ),
        SizedBox(
          height: 10,
        ),
        Material(
          elevation: 3,
          child: TabBar(
            tabs: _tabItems,
            controller: _builderPageController,
            unselectedLabelColor: Colors.grey,
            labelColor: Colors.blueAccent,
            indicatorColor: Colors.blueAccent,
            labelStyle: TextStyle(
              fontWeight: FontWeight.w500,
              fontSize: 12.0,
            ),
            unselectedLabelStyle: TextStyle(fontWeight: FontWeight.normal, fontSize: 12.0),
          ),
        ),
        Container(
            padding: EdgeInsets.symmetric(horizontal: 16.0),
            child: Builder(
              builder: (context) {
                return _tabs[selectedtabIndex];
              },
            ))
      ],
    );
  }

  void _initTabController() {
    // inits Tabcontroller for Tabview
    _builderPageController = TabController(
      length: 3,
      vsync: this,
      initialIndex: selectedtabIndex,
    );
    _builderPageController.addListener(() {
      // updated index and calls the set state
      // to switch the content of the tab based on the index clicked
      selectedtabIndex = _builderPageController.index;
      setState(() {
        _builderPageController.index;
      });
    });
  }

  void _setUpTabComponents() {
    // sets up Tab headers
    _tabItems = [
      Tab(child: Text('Tab1')),
      Tab(child: Text('Tab2')),
      Tab(child: Text('Tab3')),
    ];
  }

  List<Widget> _preprareTabItems() {
    // views to show on each tab
    // remove height once you add your contents
    return _tabs = <Widget>[
      Container(
        // first tab content
        height: 400,
        color: Colors.white,
      ),
      Container(
        // second tab content
        height: 600,
        color: Colors.white,
      ),
      Container(
        // third  tab content
        height: 900,
        color: Colors.white,
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(child: _showWidgets());
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM