Flutter:SingleChildScrollView 内的 TabBarView
Posted
技术标签:
【中文标题】Flutter:SingleChildScrollView 内的 TabBarView【英文标题】:Flutter: TabBarView inside SingleChildScrollView 【发布时间】:2020-10-10 13:51:38 【问题描述】:我的问题是我想要一个 TabBarView 在 SingleChildScrollView 中,但它给了我这个错误:
RenderFlex
孩子有非零弹性,但传入的高度限制是无限的。
如果我删除 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()
]),
),)
],
),
));
【问题讨论】:
你能解决这个问题吗? 如何解决这个问题? 【参考方案1】:我遇到了类似的问题。我的解决方案是使用容器而不是 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());
【讨论】:
【参考方案2】:您可以使用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(),
],
),
),
)
更多解释请参考this answer
【讨论】:
这woooooorrrrkkksssssss....终于。谢谢REVERIE!【参考方案3】:TabBarView 需要 SingleChildScrollView 无法提供的有限高度。问题是您在 SingleChildScrollView 内的列中使用扩展。
similar question 的回答可能对您有所帮助
答案就在错误本身。当列在可滚动的视图内时,列会尝试收缩包装其内容,但由于您使用 Expanded 作为列的子级,它的工作方式与尝试收缩其子级的列相反。两者都试图完成一个完全相反的任务。呵呵
这是导致此错误的原因,因为这两个指令彼此完全相反。
如错误日志中所述,请尝试以下操作:
考虑将mainAxisSize
设置为MainAxisSize.min
(用于列)并使用FlexFit.loose
适合灵活(使用灵活而不是扩展)。
【讨论】:
我试了一下,同样的错误。我在帖子中推送新代码。我是怎么做到的? 一次性使用容器给 TabBarView 一些高度 当然它适用于高度,但我想要一个扩展的TabBarView
做一件事从脚手架的顶部移除 singlechildscrollview 并将 Flexible 替换为 Expanded。在 Expanded 中保留 singlechildscrollview,然后是 TabBarView
它不起作用,我也想要里面的TabBar
。我将更改添加到帖子中以上是关于Flutter:SingleChildScrollView 内的 TabBarView的主要内容,如果未能解决你的问题,请参考以下文章
[Flutter] flutter项目一直卡在 Running Gradle task 'assembleDebug'...
flutter 日志输出,Flutter打印日志,flutter log,flutter 真机日志
Flutter开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )
如何解决flutter gradle build error?C:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 991