具有动态容器高度的 TabBarView [英] TabBarView with dynamic Container height
问题描述
这就是我的布局结构
这是主屏幕
ListView(
children: <Widget>[
_buildCarousel(),
_buildHomeTabBar(),
],
)
这是 HomeTabBar 屏幕
And this is the HomeTabBar screen
SingleChildScrollView(
child:
DefaultTabController(
length: myTabs.length,
initialIndex: 0,
child: Column(
children: [
TabBar(
isScrollable: true,
tabs: myTabs,
),
Container(
height: 600,
child:
TabBarView(
children: [
ChildScreen(),
ChildScreen2(),
ChildScreen3(),
],
)
)
],
))
);
我想摆脱 Container
的高度.我们如何做到这一点?
I want to get rid off that Container
height. How do we do this?
ChildScreen
正在从 REST 中获取数据,它实际上是一个 GridView.Builder
,所以 Container
的高度应该是动态的.
The ChildScreen
is getting the data from REST it is actually a GridView.Builder
so the height of Container
should be dynamic.
抱歉,我错过了 ChildScreen
的布局,实际上是这样的
Sorry I missed layout for ChildScreen
actually like this
SingleChildScrollView(
// shrinkWrap: true,
child: Column(
children: <Widget>[
StreamBuilder(
stream: categoryBloc.categoryList,
builder: (context, AsyncSnapshot<List<Category>> snapshot){
if (snapshot.hasData && snapshot!=null) {
if(snapshot.data.length > 0){
return buildCategoryList(snapshot);
}
else if(snapshot.data.length==0){
return Text('No Data');
}
}
else if (snapshot.hasError) {
return ErrorScreen(errMessage: snapshot.error.toString());
}
return Center(child: CircularProgressIndicator());
},
),
]
)
);
所以 StreamBuilder
内部是 GridView.Builder
.我要删除 Container
高度的主要内容.在不同的设备上看起来很难看...
So inside StreamBuilder
is GridView.Builder
.
The main thing I want to remove Container
height. It looks ugly on different devices...
因此,如果我删除高度,它将不会显示在屏幕上并引发错误
So if I remove the height it will not show on screen and throw error
I/flutter (493): #2 RenderObject.layout (package:flutter/src/rendering/object.dart:1578:12)I/flutter(493):#3 RenderSliverList.performLayout.advance(包:flutter/src/rendering/sliver_list.dart:200:17)I/flutter (493): #4 RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:233:19)I/flutter (493): #5 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)I/flutter (493): #6 RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:182:11)I/flutter (493): #7 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)I/flutter (493): #8 RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:405:13)I/flutter (493): #9 RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1316:12)I/flutter (493): #10 RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1234:20)I/flutter (493): #11 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)I/flutter (493): #12 _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13)I/flutter (493): #13 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
I/flutter ( 493): #2 RenderObject.layout (package:flutter/src/rendering/object.dart:1578:12) I/flutter ( 493): #3 RenderSliverList.performLayout.advance (package:flutter/src/rendering/sliver_list.dart:200:17) I/flutter ( 493): #4 RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:233:19) I/flutter ( 493): #5 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7) I/flutter ( 493): #6 RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:182:11) I/flutter ( 493): #7 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7) I/flutter ( 493): #8 RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:405:13) I/flutter ( 493): #9 RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1316:12) I/flutter ( 493): #10 RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1234:20) I/flutter ( 493): #11 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7) I/flutter ( 493): #12 _RenderProxyBox&RenderBox&RenderObjectWithChildMixin&RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:104:13) I/flutter ( 493): #13 RenderObject.layout (package:flutter/src/rendering/object.dart:1634:7)
推荐答案
我的项目中有类似的任务.问题的根源是您试图将 TabBarView
(试图尽可能大的可滚动小部件)放在没有高度的列小部件中.
I had similar task at my project. The root of the problem is that you are trying to put TabBarView
(scrollable widget that trying to be as big as possible), in a column widget, that have no height.
其中一个解决方案是在此示例 ListView
+ Column
中去掉包裹 TabBarView
的可滚动小部件.并使用 NestedScrollView
代替它们.您需要将 _buildCarousel()
和 TabBar
放在 headerSliverBuilder
部分,并将 TabBarView
放在 NestedScrollView
.
One of solutions is get rid of scrollable widgets that wraps your TabBarView
in this example ListView
+ Column
. And use NestedScrollView
instead of them. You need to put _buildCarousel()
and TabBar
in the headerSliverBuilder
part, and TabBarView
inside the body of NestedScrollView
.
我不知道您的设计看起来如何,但 NestedScrollView
默认情况下会打开 100% 的屏幕视图高度.因此,如果您想使所有内容都在一个屏幕上,只需在需要时更改 ScrollController
行为即可更轻松地阻止滚动.
I don't know how is your design looks, but NestedScrollView
by default opens up to 100% height of screen view. So if you want to make an effect that everything is on one screen, it easer to just block scrolling, by change ScrollController
behavior when it’s needed.
在此示例中,我阻止了第三个选项卡上的滚动,但您可以检查网格视图的最后一项的可见性.只需将键添加到最后一项,并检查其在屏幕上的位置.
In this example I’m blocking scrolling on third tab, but you can check visibility of the last item of the grid view. Just add the key to the last item, and check its position on the screen.
希望对你有所帮助.
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
final bodyGlobalKey = GlobalKey();
final List<Widget> myTabs = [
Tab(text: 'auto short'),
Tab(text: 'auto long'),
Tab(text: 'fixed'),
];
TabController _tabController;
ScrollController _scrollController;
bool fixedScroll;
Widget _buildCarousel() {
return Stack(
children: <Widget>[
Placeholder(fallbackHeight: 100),
Positioned.fill(child: Align(alignment: Alignment.center, child: Text('Slider'))),
],
);
}
@override
void initState() {
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
_tabController = TabController(length: 3, vsync: this);
_tabController.addListener(_smoothScrollToTop);
super.initState();
}
@override
void dispose() {
_tabController.dispose();
_scrollController.dispose();
super.dispose();
}
_scrollListener() {
if (fixedScroll) {
_scrollController.jumpTo(0);
}
}
_smoothScrollToTop() {
_scrollController.animateTo(
0,
duration: Duration(microseconds: 300),
curve: Curves.ease,
);
setState(() {
fixedScroll = _tabController.index == 2;
});
}
_buildTabContext(int lineCount) => Container(
child: ListView.builder(
physics: const ClampingScrollPhysics(),
itemCount: lineCount,
itemBuilder: (BuildContext context, int index) {
return Text('some content');
},
),
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(child: _buildCarousel()),
SliverToBoxAdapter(
child: TabBar(
controller: _tabController,
labelColor: Colors.redAccent,
isScrollable: true,
tabs: myTabs,
),
),
];
},
body: Container(
child: TabBarView(
controller: _tabController,
children: [_buildTabContext(2), _buildTabContext(200), _buildTabContext(2)],
),
),
),
);
}
}
.
另一种获得所需内容的方法是创建自定义 TabView
小部件.
Another way to get what you want could be creating custom TabView
widget.
这篇关于具有动态容器高度的 TabBarView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!