Home > Enterprise >  How to make a screen with Tabs and TabBarViews both scrollable in flutter?
How to make a screen with Tabs and TabBarViews both scrollable in flutter?

Time:07-18

I've been trying to add SingleChildScrollView to my code so that the whole page including Tabs and TabBarViews are scrolled together.

RenderFlex children have non-zero flex but incoming height constraints are unbounded Horizontal viewport was given unbounded height.

These are the errors I encountered to make the whole page scrollable.

import 'package:buttons_tabbar/buttons_tabbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';

import '../widgets/style_grid.dart';

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

  @override
  State<StyleScreen> createState() => _StyleScreenState();
}

class _StyleScreenState extends State<StyleScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Screen')),
      body: SafeArea(
        child: DefaultTabController(
          length: 5,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              ButtonsTabBar(
                backgroundColor: Colors.grey[300],
                radius: 16,
                unselectedLabelStyle: TextStyle(color: Colors.black),
                labelStyle: TextStyle(
                    color: Colors.orange, fontWeight: FontWeight.bold),
                tabs: [
                  Tab(
                    icon: Icon(Icons.directions_car),
                    text: "All",
                  ),
                  Tab(
                    icon: Icon(Icons.directions_transit),
                    text: "Cat1",
                  ),
                  Tab(
                    icon: Icon(Icons.directions_transit),
                    text: "Cat2",
                  ),
                  Tab(
                    icon: Icon(Icons.directions_transit),
                    text: "Cat3",
                  ),
                  Tab(
                    icon: Icon(Icons.directions_transit),
                    text: "Cat4",
                  ),
                ],
              ),
              Expanded(
                child: TabBarView(
                  physics: NeverScrollableScrollPhysics(),
                  children: <Widget>[
                    StyleGrid(),
                    StyleGrid(),
                    StyleGrid(),
                    StyleGrid(),
                    StyleGrid(),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

I want to make the red area scrollable.

CodePudding user response:

Try wrapping it in the following class. This provides both vertical and horizontal scrolling.

class ScrollableWidget extends StatelessWidget {
      final Widget child;
    
      const ScrollableWidget({Key? key, required this.child}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => SingleChildScrollView(
            physics: const BouncingScrollPhysics(),
            scrollDirection: Axis.horizontal,
            child: SingleChildScrollView(
              physics: const BouncingScrollPhysics(),
              scrollDirection: Axis.vertical,
              child: child,
            ),
          );
    }

CodePudding user response:

You can use NestedScrollView. It is better to use ListView.builder or CustomScrollView instead of using SingleChildScrollView on StyleGrid

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

  @override
  State<StyleScreen> createState() => _StyleScreenState();
}

class _StyleScreenState extends State<StyleScreen>
    with SingleTickerProviderStateMixin {
  late final TabController controller = TabController(length: 5, vsync: this);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Screen')),
      body: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [
          SliverToBoxAdapter(
            child: tabBar(),
          )
        ],
        body: TabBarView(
          controller: controller,
          children: List.generate(
              5, (index) => SingleChildScrollView(child: StyleGrid())),
        ),
      ),
    );
  }

  ButtonsTabBar tabBar() {
    return ButtonsTabBar(
      controller: controller,
      backgroundColor: Colors.grey[300],
      radius: 16,
      unselectedLabelStyle: TextStyle(color: Colors.black),
      labelStyle: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
      tabs: [
        Tab(
          icon: Icon(Icons.directions_car),
          text: "All",
        ),
        Tab(
          icon: Icon(Icons.directions_transit),
          text: "Cat1",
        ),
        Tab(
          icon: Icon(Icons.directions_transit),
          text: "Cat2",
        ),
        Tab(
          icon: Icon(Icons.directions_transit),
          text: "Cat3",
        ),
        Tab(
          icon: Icon(Icons.directions_transit),
          text: "Cat4",
        ),
      ],
    );
  }
}

  • Related