So this is my layout structure
This is the main screen
ListView( children: <Widget>[ _buildCarousel(), _buildHomeTabBar(), ], )
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(), ], ) ) ], )) );
I want to get rid off that Container
height. How do we do this?
The ChildScreen
is getting the data from REST it is actually a GridView.Builder
so the height of Container
should be dynamic.
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()); }, ), ] ) );
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 (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)
TabBar is used to create the tabs, while TabBarView is used to define the content of each tab. Flutter already handles how to switch between tabs, which makes it easier for us. In addition, Flutter also makes it possible to customize the style and behavior of the tab layout.
To create a tab in it, create a tab list and create an object of its TabController. TabController _tabController; Initalize the TabController inside the initState() method and also override it in the dispose() method.
DefaultTabController is an inherited widget that is used to share a TabController with a TabBar or a TabBarView. It's used when sharing an explicitly created TabController isn't convenient because the tab bar widgets are created by a stateless parent widget or by different parent widgets.
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.
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
.
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.
Hope it’s help.
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)], ), ), ), ); } }
.
Another way to get what you want could be creating custom TabView
widget.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With