繁体   English   中英

Flutter:SingleChildScrollView 内的 TabBarView

[英]Flutter: TabBarView inside SingleChildScrollView

我的问题是我想要一个 TabBarView 在 SingleChildScrollView 中,但它给了我这个错误: RenderFlex children have non-zero flex 但传入的高度约束是无限的。

如果我删除SingleChildScrollView它可以工作,但我需要小部件,因为那时我想推送一个 ListView ,它与TabBar一起滚动,比如 Instagram。

代码:

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

变化:

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

您可以使用NestedScrollView来解决此问题。

下面的代码帮助我解决了:

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

如需进一步解释,请参阅此答案

TabBarView 需要 SingleChildScrollView 无法提供的有限高度。 问题是您在 SingleChildScrollView 内的列中使用扩展。


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

答案就在错误本身。 当列在可滚动的视图内时,该列正在尝试收缩包装其内容,但由于您使用 Expanded 作为该列的子级,它的工作方式与尝试收缩其子级的列相反。 两者都试图完成一个完全相反的任务。 OG

这是导致此错误的原因,因为这两个指令彼此完全相反。 如错误日志中所述,请尝试以下操作:考虑将mainAxisSize设置为MainAxisSize.min (用于列)并使用FlexFit.loose进行灵活拟合(使用 Flexible 而不是 Expanded)。

我遇到了类似的问题。 我的解决方案是使用容器而不是 TabBarView 来显示子项(选项卡)。

您可以根据通过 TabBar 选择的索引来切换此容器的内容。

当然,如果您需要滑动手势在选项卡之间移动,您也需要添加它,对我来说这不是必需的。 代码看起来像这样。

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