Search code examples
flutterdartmobile

Making TabBarView take up the remainder of the Screen


I want to display TabBar in a screen point in which it take the remaining space of the screen. While doing that, I aim to display two GridViews in a two tabs of that TabBar

When I use an Expanded Widget it causes the app the crash, it only works if I use a SizedBox with height constraints.

Here is the code

import 'package:bespoked_1_1/utils/constants.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class SellersHomePage extends StatefulWidget {
  const SellersHomePage({super.key});

  @override
  State<SellersHomePage> createState() => _SellersHomePageState();
}

class _SellersHomePageState extends State<SellersHomePage> {
  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        title: Text('Epoxy Forever'),
        centerTitle: true,
        actions: [
          IconButton(
            onPressed: () {},
            icon: Icon(
              Icons.ios_share,
            ),
          ),
          IconButton(
            onPressed: () {},
            icon: Icon(
              Icons.shopping_cart_outlined,
            ),
          ),
        ],
      ),
      body: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Stack(
            children: [
              SizedBox(
                height: screenHeight * 0.3,
                width: screenWidth,
                child: ShaderMask(
                  shaderCallback: (rect) {
                    return LinearGradient(
                      begin: Alignment.topCenter,
                      end: Alignment.bottomCenter,
                      colors: const [Colors.black, Colors.transparent],
                    ).createShader(
                        Rect.fromLTRB(0, 0, rect.width, rect.height));
                  },
                  blendMode: BlendMode.dstIn,
                  child: Image(
                    fit: BoxFit
                        .cover, //TODO: Give the option to change the fit of the image
                    height: screenHeight * 0.2,
                    image: NetworkImage(
                        'https://img.freepik.com/free-photo/carpenter-cutting-mdf-board-inside-workshop_23-2149451051.jpg'),
                  ),
                ),
              ),

              //sellers logo and details
              Positioned(
                top: 20,
                left: 0,
                right: 0,
                child: Padding(
                  padding: const EdgeInsets.all(20.0),
                  child: Column(
                    children: const [
                      //profile image
                      CircleAvatar(
                        radius: 50,
                        backgroundImage: NetworkImage(
                            'https://t3.ftcdn.net/jpg/01/37/76/72/360_F_137767250_pocwIHgKu5rDuYFDNCTNcPy77gHb1lfh.jpg'),
                      ),

                      //name
                      Text(
                        'Karls Carpentry',
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 24),
                      ),

                      //sub heading
                      Text(
                        'Specialist in Fine custom furniture and upholstery',
                        style: TextStyle(fontSize: 16),
                        textAlign: TextAlign.center,
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),

          //business stats
          Center(
            child: Container(
              margin: EdgeInsets.symmetric(horizontal: 30),
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(25), color: Colors.grey),
              padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10),
              child: const Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  //avg rating
                  Column(
                    children: [
                      Text(
                        '4.8',
                        style: TextStyle(fontSize: 24),
                      ),
                      Text('Avg Rating')
                    ],
                  ),

                  //followers
                  Column(
                    children: [
                      Text(
                        '28',
                        style: TextStyle(fontSize: 24),
                      ),
                      Text('Avg Rating')
                    ],
                  ),

                  //callouts and items sold
                  Column(
                    children: [
                      Text(
                        '200',
                        style: TextStyle(fontSize: 24),
                      ),
                      Text('Avg Rating')
                    ],
                  )
                ],
              ),
            ),
          ),

          DefaultTabController(
            length: 3,
            child: Column(
              children: [
                //tabs
                TabBar(indicatorSize: TabBarIndicatorSize.tab, tabs: [
                  Tab(
                    text: 'Shop',
                  ),
                  Tab(
                    text: 'Posts',
                  ),
                  Tab(
                    text: 'About',
                  ),
                ]),

                //tabviews
                TabBarView(children: [
                  Icon(Icons.shop),
                  Icon(Icons.image),
                  Icon(Icons.info)
                ])
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Solution

  • Try the following, it's your code but added what you want.

    To make the TabBar allocate the remaining space of the screen, wrap it with Expanded widget.

    Also, there are two tabs with that hold a scrollable Grid layout:

    class SellersHomePage extends StatefulWidget {
      const SellersHomePage({super.key});
    
      @override
      State<SellersHomePage> createState() => _SellersHomePageState();
    }
    
    class _SellersHomePageState extends State<SellersHomePage> {
      @override
      Widget build(BuildContext context) {
        final screenWidth = MediaQuery.of(context).size.width;
        final screenHeight = MediaQuery.of(context).size.height;
        return DefaultTabController(
          length: 3,
          child: Scaffold(
            appBar: AppBar(
              title: Text('Epoxy Forever'),
              centerTitle: true,
              actions: [
                IconButton(
                  onPressed: () {},
                  icon: Icon(
                    Icons.ios_share,
                  ),
                ),
                IconButton(
                  onPressed: () {},
                  icon: Icon(
                    Icons.shopping_cart_outlined,
                  ),
                ),
              ],
            ),
            body: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Stack(
                  children: [
                    SizedBox(
                      height: screenHeight * 0.3,
                      width: screenWidth,
                      child: ShaderMask(
                        shaderCallback: (rect) {
                          return LinearGradient(
                            begin: Alignment.topCenter,
                            end: Alignment.bottomCenter,
                            colors: const [Colors.black, Colors.transparent],
                          ).createShader(
                              Rect.fromLTRB(0, 0, rect.width, rect.height));
                        },
                        blendMode: BlendMode.dstIn,
                        child: Image(
                          fit: BoxFit
                              .cover, //TODO: Give the option to change the fit of the image
                          height: screenHeight * 0.2,
                          image: NetworkImage(
                              'https://img.freepik.com/free-photo/carpenter-cutting-mdf-board-inside-workshop_23-2149451051.jpg'),
                        ),
                      ),
                    ),
    
                    //sellers logo and details
                    Positioned(
                      top: 20,
                      left: 0,
                      right: 0,
                      child: Padding(
                        padding: const EdgeInsets.all(20.0),
                        child: Column(
                          children: const [
                            //profile image
                            CircleAvatar(
                              radius: 50,
                              backgroundImage: NetworkImage(
                                  'https://t3.ftcdn.net/jpg/01/37/76/72/360_F_137767250_pocwIHgKu5rDuYFDNCTNcPy77gHb1lfh.jpg'),
                            ),
    
                            //name
                            Text(
                              'Karls Carpentry',
                              style: TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 24),
                            ),
    
                            //sub heading
                            Text(
                              'Specialist in Fine custom furniture and upholstery',
                              style: TextStyle(fontSize: 16),
                              textAlign: TextAlign.center,
                            ),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
    
                //business stats
                Center(
                  child: Container(
                    margin: EdgeInsets.symmetric(horizontal: 30),
                    decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(25), color: Colors.grey),
                    padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10),
                    child:  Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        //avg rating
                        Column(
                          children: [
                            Text(
                              '4.8',
                              style: TextStyle(fontSize: 24),
                            ),
                            Text('Avg Rating')
                          ],
                        ),
    
                        //followers
                        Column(
                          children: [
                            Text(
                              '28',
                              style: TextStyle(fontSize: 24),
                            ),
                            Text('Avg Rating')
                          ],
                        ),
    
                        //callouts and items sold
                        Column(
                          children: [
                            Text(
                              '200',
                              style: TextStyle(fontSize: 24),
                            ),
                            Text('Avg Rating')
                          ],
                        )
                      ],
                    ),
                  ),
                ),
    
                Expanded(
                  child: Column(
                    children: [
                      //tabs
                      TabBar(indicatorSize: TabBarIndicatorSize.tab, tabs: [
                        Tab(
                          text: 'Shop',
                        
                        ),
                        Tab(
                          text: 'Posts',
                        ),
                        Tab(
                          text: 'About',
                        ),
                      ]),
    
                      //tabviews
                      Expanded(
                        child: TabBarView(children: [
                          GridView.builder(
                            itemBuilder: (context,index)=>Container(color: Colors.yellow),
                            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                              crossAxisCount: 3,
                              crossAxisSpacing: 10,
                              mainAxisSpacing: 10,
                            ),
                          ),
                          
    
                          GridView.builder(
                            itemBuilder: (context,index)=>Container(color: Colors.purple),
                            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                              crossAxisCount: 3,
                              crossAxisSpacing: 10,
                              mainAxisSpacing: 10,
                            ),
                          ),
                          Icon(Icons.info)
                        ]),
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    

    First Tab

    enter image description here

    Second Tab

    enter image description here

    Note: Tabs are underlined with the blue solid line, but their labels needs styling, handle it in your theme.