1

I got it working somehow, but the scroll feature is gone:

return Scaffold(
      body: DefaultTabController(
        length: 2,
        child: ListView(
          children: <Widget>[
            Container(
              height: 120,
              child: Center(
                child: Text('something on top'),
              ),
            ),
            TabBar(
              // controller: _tabController,
              labelColor: Colors.redAccent,
              isScrollable: true,
              tabs: [
                Tab(text: "Finished"), // TODO: translate
                Tab(text: "In progress"), // TODO: translate
              ],
            ),
            Center(
              child: [
                Text('second tab1232'),
                Text('second tab111'),
                Column(
                  children: List.generate(20, (index) => Text('line: $index'))
                      .toList(),
                ),
                Text('third tab')
              ][0], // change this
            ),
            Container(child: Text('another component')),
          ],
        ),
      ),
    );

Note: check the [0] that I simplified.

Not sure if I can fix the scroll from this or if I need to take a totally different approach.

Example of content scroll working with the original way: https://flutter.dev/docs/cookbook/design/tabs

Dani
  • 3,128
  • 2
  • 43
  • 91

2 Answers2

0

Check out this other answer solves the problem: https://stackoverflow.com/a/57383014/12334012

man of knowledge
  • 1,077
  • 7
  • 13
  • so I come back to the original problem: the dynamic height. I cannot have a fixed height for the content. I have dynamic lists for each tabs and I should not have vertical scroll for them. For this scenario I'd prefer to stick to my solution and lose the horizontal scroll for the content rather than losing the dynamic height – Dani May 31 '21 at 14:28
  • So okay, you want pages to have dynamic height ? – man of knowledge May 31 '21 at 14:31
  • 1
    yes, the content of each tab should have a dynamic height – Dani May 31 '21 at 14:31
  • 1
    hm, let me think. – man of knowledge May 31 '21 at 14:32
  • Have you seen this, https://stackoverflow.com/questions/54642710/tabbarview-with-dynamic-container-height ? – man of knowledge May 31 '21 at 14:45
  • I tried this option before. The problem with it is that the TabBarView is not pushing the widgets below it. If I put the TabBarView and a new element inside a Column, the TabBarView needs to be wrapped with a expanded widget, and this again would take an unnecessary space for a small content. I'll keep playing with it to see if I find something else – Dani May 31 '21 at 15:08
  • 1
    This red are takes the full height: https://i.ibb.co/YXwMVPy/Screenshot-2021-05-31-at-17-35-57.png – Dani May 31 '21 at 15:36
  • did you find any solution @Dani – hio Sep 07 '22 at 05:09
  • check the new answer – Dani Sep 08 '22 at 21:34
0

With this we don't have the swipe and its animation but it could be created by some other widgets. It works with a dynamic height anyway:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class OptionsScreen extends StatefulWidget {
  const OptionsScreen({Key? key}) : super(key: key);
  @override
  OptionsScreenState createState() => OptionsScreenState();
}

class OptionsScreenState extends State<OptionsScreen> {
  final bodyGlobalKey = GlobalKey();
  late var streamFunction;

  @override
  void initState() {
    streamFunction = delayFunction;
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  Stream<int> delayFunction = (() async* {
    for (int i = 1; i <= 3; i++) {
      await Future<void>.delayed(const Duration(seconds: 1));
      yield i;
    }
  })();

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: streamFunction,
      builder: (BuildContext context, snapshot) {
        if (snapshot.hasError) return Text('Error: ${snapshot.error}');
        if (!snapshot.hasData) return const Text('loading...');
        if (snapshot.data == null) return Container();

        // return tabs();
        return const CustomTabs();
      },
    );
  }
}

class CustomTabs extends StatefulWidget {
  const CustomTabs({Key? key}) : super(key: key);

  @override
  State<CustomTabs> createState() => _CustomTabsState();
}

class _CustomTabsState extends State<CustomTabs>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    _tabController = TabController(length: 3, vsync: this);
    super.initState();
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            TabBar(
              isScrollable: true,
              controller: _tabController,
              // COMMENT FOR WAY B
              onTap: (int index) {
                setState(() {
                  _tabController.animateTo(index);
                });
              },
              labelColor: Theme.of(context).primaryColor,
              indicator: UnderlineTabIndicator(
                borderSide: BorderSide(
                  color: Theme.of(context).primaryColor,
                ),
              ),
              tabs: [
                Tab(text: '1'),
                Tab(text: '2'),
                Tab(text: '3'),
              ],
            ),
            // WAY A
            // THIS WAY HAS NO ANIMATION BUT IT HAS DYNAMIC HEIGHT
            // SetState TRIGGERS STREAMBUILDER WITH TAB CHANGES
            Column(
              children: [
                Visibility(
                  visible: _tabController.index == 0,
                  child: const Text('1111'),
                ),
                Visibility(
                  visible: _tabController.index == 1,
                  child: Column(
                    children: const [
                      Text('2222'),
                      Text('2222'),
                      Text('2222'),
                      Text('2222'),
                      Text('2222'),
                      Text('2222'),
                    ],
                  ),
                ),
                Visibility(
                  visible: _tabController.index == 2,
                  child: const Text('33333'),
                ),
                const Text('This is a different widget. Tabs will push it down')
              ],
            ),
            // THIS WAY HAS NO DYNAMIC HEIGHT BUT IT HAS ANIMATION
            // STREAMBUILDER ONLY TRIGGERS FIRST TIME
            // Container(
            //   color: Colors.red,
            //   height: 200,
            //   padding: const EdgeInsets.only(top: 8.0),
            //   child: TabBarView(
            //     controller: _tabController,
            //     children: [
            //       const Text('1111'),
            //       Column(
            //         children: const [
            //           Text('2222'),
            //           Text('2222'),
            //           Text('2222'),
            //           Text('2222'),
            //         ],
            //       ),
            //       const Text('3333'),
            //     ],
            //   ),
            // ),
          ],
        ),
      ],
    );
  }
}
Dani
  • 3,128
  • 2
  • 43
  • 91