Flutter: TabBarView inside SingleChildScrollView

5,645

Solution 1

You can use NestedScrollView to fix this issue.

The below code helped me to solve:

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(),
        ],
      ),
    ),
  )

For further explanation, refer to this answer

Solution 2

The TabBarView requires a finite height which the SingleChildScrollView cant offer. The Problem is you are using expanded in a column that is inside a SingleChildScrollView.


This answer from a similar question might help you

The answer is in the error itself. When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded as a child of the column it is working opposite to the column trying to shrink-wrap its children. Both are trying to achieve an exactly opposite task. Og

This is causing this error because these two directives are completely opposite to each other. As mentioned in the error logs try the following: Consider setting mainAxisSize to MainAxisSize.min (for column) and using FlexFit.loose fits for the flexible (use Flexible rather than Expanded).

Share:
5,645
Dani Herrero
Author by

Dani Herrero

Updated on December 21, 2022

Comments

  • Dani Herrero
    Dani Herrero over 1 year

    My problem is that I want a TabBarView inside a SingleChildScrollView but it gives me this error: RenderFlex children have non-zero flex but incoming height constraints are unbounded.

    If I remove the SingleChildScrollView it works but I need the widget because then I want to push a ListView that it scrolls with the TabBar, like Instagram.

    Code:

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

    Changes:

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