Search code examples
flutterdartlistviewtabviewscrollable

Tabview scroll behavior


I've a Tabview along with a list of azlist scrollable bar. When scrolling through the azlist bar, the TabView moves along easily trying to slide to another Tab. I want the TabView to be stay put during scrolling of the azlist scrollable bar. Is there a way to prevent this behavior for TabView ? I've tried declare a CustomScrollPhysic but it just didn't work the way I want it to be.

Below are attached gif & code for it.

enter image description here

import this in pubspec

alphabet_list_view: ^0.1.2

home.dart

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


class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          bottom: const TabBar(
            isScrollable: true,
            tabs: [
              Tab(text: 'TabOne'),
              Tab(text: 'TabTwo'),
            ],
          ),
        ),
        body: SafeArea(
          child: TabBarView(
            physics: CustomScrollPhysics(),
            children: [
              TabOne(),
              TabTwo(),
            ],
          ),
        ),
      ),
    );
  }
}

tabone.dart

class TabOne extends StatelessWidget {
  TabOne({Key? key}) : super(key: key);

  final List<AlphabetListViewItemGroup> animals = [
    for (var animalLetter in animalsMap.entries)
      AlphabetListViewItemGroup(
        tag: animalLetter.key,
        children: animalLetter.value.map((animal) => Text(animal)).toList(),
      ),
  ];

  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.rtl,
      child: AlphabetListView(
        items: animals,
      ),
    );
  }
}

tabtwo.dart


class TabTwo extends StatelessWidget {
  TabTwo({Key? key}) : super(key: key);

  final List<AlphabetListViewItemGroup> animals = [
    for (var animalLetter in animalsMap.entries)
      AlphabetListViewItemGroup(
        tag: animalLetter.key,
        children: animalLetter.value.map((animal) => Text(animal)).toList(),
      ),
  ];

  @override
  Widget build(BuildContext context) {
    return AlphabetListView(
      items: animals,
    );
  }
}

custom_scroll_physics.dart


class CustomScrollPhysics extends ScrollPhysics {
  const CustomScrollPhysics({ScrollPhysics? parent}) : super(parent: parent);

  @override
  ScrollPhysics applyTo(ScrollPhysics? ancestor) =>
      CustomScrollPhysics(parent: buildParent(ancestor));

  @override
  Simulation? createBallisticSimulation(
      ScrollMetrics position, double velocity) {
    final tolerance = this.tolerance;
    if ((velocity.abs() < tolerance.velocity) ||
        (velocity > 0.0 && position.pixels >= position.maxScrollExtent) ||
        (velocity < 0.0 && position.pixels <= position.minScrollExtent)) {
      return null;
    }
    return ClampingScrollSimulation(
      position: position.pixels,
      velocity: velocity,
      friction: 0.5,
      tolerance: Tolerance.defaultTolerance,
    );
  }
}

hardcoded maps of animals


const Map<String, List<String>> animalsMap = {
  'A': [
    'Admiral, indian red',
  ],
  'B': [
    'Baboon, gelada',
    'Baboon, olive',
  ],
  'F': [
    'Fairy penguin',
    'Falcon, peregrine',
    'Frog (unidentified)',
  ],
  'G': [
    'Galah',
    'Galapagos albatross',
  ],
  'H': [
    'Hare, arctic',
    'Hartebeest, coke\'s',
  ],
  'I': [
    'Ibis, glossy',
    'Insect, stick',
  ],
  'J': [
    'Jacana, african',
    'Jackal, black-backed',
  ],
  'K': [
    'Kaffir cat',
    'Kafue flats lechwe',
    'Koala',
  ],
  'M': [
    'Macaque, pig-tailed',
    'Musk ox',
    'Mynah, indian',
  ],
  'N': [
    'Native cat',
    'Nighthawk, common',
  ],
  'P': [
    'Painted stork',
    'Porcupine, prehensile-tailed',
  ],
  'Q': [
    'Quoll, spotted-tailed',
  ],
  'T': [
    'Tailless tenrec',
    'Tapir, brazilian',
    'Tarantula, salmon pink bird eater',
  ],
  'U': [
    'Uinta ground squirrel',
  ],
  'V': [
    'Vicuna',
    'Vine snake (unidentified)',
  ],
  'W': [
    'Wagtail, african pied',
    'White-fronted capuchin',
    'Woylie',
  ],
  'Y': [
    'Yak',
  ],
  'Z': [
    'Zebra, plains',
    'Zorilla',
    'Zorro, common',
  ],
};

Solution

  • I have a very similar page: two tabs both containing alphabet lists and the scrolling are working well.

    I do not have a CustomScrollPhysics on my widgets, but use a TabController.

    class _PeopleListScreenState extends State<PeopleListScreen> with SingleTickerProviderStateMixin {
      late TabController _tabController;
      var tab = _Tab.user;
    
      @override
      void initState() {
        super.initState();
        _tabController = TabController(vsync: this, length: 2);
        _tabController.addListener(() {
          if (_tabController.indexIsChanging || _tabController.index != _tabController.previousIndex) {
            var index = _tabController.index;
            // Tab Changed tapping on new tab
            setState(() => tab = _Tab.values[index]);
          }
        });
      }
    
      @override
      void dispose() {
        _tabController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Column(
            children: [
              TabBar(
                controller: tabController,
                tabs: [Tab(), Tab()],
              ),
              Expanded(
                child: TabBarView(
                  tabController: _tabController,
                  children: [AlphabetList(), AlphabetList()],
                ),
              ),
            ],
          ),
        );
      }
    }