Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TabBarView with dynamic Container height

Tags:

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)

like image 645
stuckedoverflow Avatar asked Feb 12 '19 04:02

stuckedoverflow


People also ask

What is TabBarView flutter?

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.

How do you use TabController in flutter?

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.

What is DefaultTabController in flutter?

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.


1 Answers

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

enter image description here .

Another way to get what you want could be creating custom TabView widget.

like image 124
Kherel Avatar answered Sep 21 '22 16:09

Kherel