cekpowell
cekpowell

Reputation: 97

TabBarView within Scrollable Page

I am having real trouble getting a layout to work within Flutter.

The layout I am trying to create:

Here is the schematic for the layout:

Example Code

Here is a minimum example code (with exact widget definitions removed):

return DefaultTabController(
      length: 2,
      child: ListView(
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    );

The Problem:

When the height of the window gets smaller, I get an overflow error at the bottom:

What I have Done:

Similar Questions that Didnt provide a working solution:

I am very confused as to why it is not working as I feel this is a very simple thing. Essentially, it is the same layout used in the Instragram app (among others) when viewing your personal profile (see: https://unblast.com/wp-content/uploads/2020/01/Instagram-UI-Profile-1.jpg).

Upvotes: 7

Views: 17938

Answers (2)

Michał Dobi Dobrzański
Michał Dobi Dobrzański

Reputation: 2000

I have scratched my head around TabBarView many times with a question 'How to put dynamic-height content inside TabBarView while it is inside a scrollable container?'

Unfortunately, it is broken for such use cases as the scroll and does not work correctly and the content overflows.

Hence, my solution answers the OP question by answering how to achieve the whole page scrollable. It replaces TabBarView with different mechanism.

My solution is to skip TabBarView and use TabBar and TabController to get a Widget from the Widget list.

Code:

// STATEFUL WIDGET CODE

late TabController tabController; // USED FOR NAVIGATION

@override
void initState() {
  tabController = TabController(
    initialIndex: 0,
    length: 3, // adjust your length
    vsync: this,
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('test')), // some app bar
    body: SingleChildScrollView(
      child: Column(
        children: [
          TabBar(controller: tabController),
          _getTabAtIndex(tabContoller.index),
        ],
      ),
    ),
  );
}

Widget _getTabAtIndex(int index) {
  var list = [
    Container(), // FIRST ITEM
    Container(), // SECOND ITEM
    Container(), // THIRD ITEM
  ];

  return list[index];
}

Upvotes: 5

griffins
griffins

Reputation: 8274

From the comments you can wrap your page in a singlechildscrollview, disable scroll physics for the listview as the parent is already scrollable.

return SingleChildScrollView(
  child: DefaultTabController(
    length: 2,
    child: ListView(
      physics: NeverScrollableScrollPhysics(),
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //
          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    ));

** Option2 **

you can use a customScrollView or a nestedScrollView

DefaultTabController(
      length: 2,
      child:
CustomScrollView(
              slivers: [

SlivertoboxAdapter(child:   // TOP CONTAINER //
          Container(height: 30),

SlivertoboxAdapter(child:   // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

//... Sliverfillremaining/slivettoboxadapter for your tabbarview

SlivertoboxAdapter(child:TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),




Upvotes: 5

Related Questions