'Disable TabView animation on Tab click event?

How can I disable TabView animation when Tab in TabBar clicked ? I added

physics: NeverScrollableScrollPhysics()

for TabView but that doesn't apply for TabBar.

I'm using DefaultTabController.



Solution 1:[1]

Based on a very good answer on github about this issue, which achieves something similar to what your looking for (but with a bottomNavigationBar) here I share with you another workaround. It consists of combining a DefaultTabController with a PageView, a PageController and a simple index. Try this out.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tabs with no animation',
      theme: ThemeData.dark(),
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  PageController _pageController;
  final int currentTab = 0;

  @override
  void initState() {
    // TODO: implement initState
    _pageController = PageController(initialPage: currentTab);
    super.initState();
  }

  final List<Tab> myTabs = <Tab>[
    Tab(text: 'One'),
    Tab(
      text: 'Two',
    ),
  ];

  var tabs = [
    TabOne(),
    TabTwo(),
  ];

  @override
  Widget build(BuildContext context) {
    var pageView = PageView(
      controller: _pageController,
      physics: NeverScrollableScrollPhysics(),
      children: tabs,
    );

    return DefaultTabController(
      length: myTabs.length,
      child: Scaffold(
          extendBodyBehindAppBar: true,
          appBar: AppBar(
            backgroundColor: Colors.transparent,
            elevation: 0.0,
            automaticallyImplyLeading: false,
            title: Center(
              child: Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(30),
                  color: Colors.grey.shade800,
                ),
                width: 200,
                height: 50,
                child: TabBar(
                  onTap: (index) {
                    _pageController.jumpToPage(index);
                  },
                  unselectedLabelColor: Colors.white,
                  indicator: BoxDecoration(
                      borderRadius: BorderRadius.circular(30),
                      color: Colors.black),
                  tabs: myTabs,
                ),
              ),
            ),
          ),
          body: pageView),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(child: Text('Tab one')),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(child: Text('Tab two')),
    );
  }
}

Doing so, you have a something identical to a TabBarView but without animation.

Solution 2:[2]

I don't think there's a way to disable the transition animation on TabBarView. As a workaround, you can use a Container that'll return different pages depending on the tab selected.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 4, vsync: this);
  }

  var _homeScaffoldKey = Key("Scaffold Key");
  var tabController;
  var currentPage = 0;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: _homeScaffoldKey,
      body: _getCustomContainer(),
      bottomNavigationBar: new Material(
        color: Colors.blue,
        child: new TabBar(
          isScrollable: true,
          indicatorColor: Color.fromRGBO(255, 25, 255, 0.0),
          controller: tabController,
          onTap: (value) {
            setState(() {
              currentPage = value;
            });
          },
          tabs: <Widget>[
            new Tab(
              icon: new Icon(Icons.accessibility),
            ),
            new Tab(
              icon: new Icon(Icons.accessibility),
            ),
            new Tab(
              icon: new Icon(Icons.accessibility),
            ),
            new Tab(
              icon: new Icon(Icons.accessibility),
            ),
          ],
        ),
      ),
    );
  }

  _getCustomContainer() {
    switch (currentPage) {
      case 0:
        return page1();
      case 1:
        return page2();
      case 2:
        return page3();
      case 3:
        return page4();
    }
  }

  page1() => Container(
        color: Colors.redAccent,
        child: Center(
          child: Text("Page 1"),
        ),
      );
  page2() => Container(
        color: Colors.greenAccent,
        child: Center(
          child: Text("Page 2"),
        ),
      );
  page3() => Container(
        color: Colors.blueAccent,
        child: Center(
          child: Text("Page 3"),
        ),
      );
  page4() => Container(
        color: Colors.yellowAccent,
        child: Center(
          child: Text("Page 4"),
        ),
      );
}

Demo

demo

Solution 3:[3]

Seems like this can be achieved using DefaultTabController easily as of 2022.

Here is my solution to this:

class _TabPageState extends State<TabPage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    // when initializing the `TabController` set `animationDuration` as `zero`.
    _tabController =
        TabController(length: 3, vsync: this, animationDuration: Duration.zero);
  }


  @override
  Widget build(BuildContext context) {
    return Container(
      color: ColorPalette.white,
      child: SafeArea(
        top: false,
        child: DefaultTabController(
          length: 3,
          child: Builder(builder: (context) {
            return Scaffold(
              bottomNavigationBar: TabBar(
                controller: _tabController, // set the tab controller of your `TabBar`
                enableFeedback: false,
                onTap: (index) {
                  setState(() {});
                },
                indicatorColor: Colors.transparent,
                tabs: [
                  TabItem(
                      selectedIndex: _tabController.index,
                      index: 0,
                      assetName: Assets.tabHome),
                  TabItem(
                      selectedIndex: _tabController.index,
                      index: 1,
                      assetName: Assets.tabCare),
                  TabItem(
                      selectedIndex: _tabController.index,
                      index: 2,
                      assetName: Assets.tabProfile),
                ],
              ),
              body: Center(
                child: TabBarView(
                  controller: _tabController, // set the controller of your `TabBarView`
                  physics: const NeverScrollableScrollPhysics(),
                  children: const [
                    ParentHomePage(),
                    ParentCarePage(),
                    ParentAccountPage()
                  ],
                ),
              ),
            );
          }),
        ),
      ),
    );
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Iván Yoed
Solution 2 Omatt
Solution 3 Ali Ersöz