Day 28: How to Preserve Tab State When Switching Tabs in Flutter with Our Noted App

Hemant Kumar Prajapati
6 min readOct 5, 2024

--

Hey Flutter friends! 👋 If you’re working on a Flutter app with a TabBar, you’ve probably noticed this frustrating quirk—whenever you switch between tabs, the state of each tab resets. For example, maybe you have a form, a counter, or some complex UI in one tab, and when you switch back to it after navigating away, all your progress is lost. 😟

This issue can ruin the user experience, especially in apps where maintaining data across different screens is crucial. The good news? There’s a way to preserve the state of your tabs as users switch between them, and it’s easier than you might think! In this post, we’ll dive deep into how to keep your TabBar state intact while switching tabs in Flutter.

Let’s get started!

| Why Does Tab State Reset in Flutter?

Before we jump into the solution, let’s quickly understand the problem.

By default, Flutter rebuilds a screen when it’s no longer visible, including when you switch between tabs. When a tab screen gets rebuilt, it loses its state because Flutter doesn’t store it unless explicitly told to do so.

This is where the concept of preserving state comes in. When you switch tabs, you want Flutter to keep track of where the user left off.

| The Key: AutomaticKeepAliveClientMixin

To solve this issue, we’ll use Flutter’s AutomaticKeepAliveClientMixin. This mixin allows the state of a widget to be preserved when the widget is not visible (like when the user switches tabs).

How Does It Work?

The AutomaticKeepAliveClientMixin tells Flutter to keep the state of a tab’s content alive even when the tab isn’t currently active.

Let’s break down how to implement this in your app step by step.

Step-by-Step Implementation

1. Basic TabBar Setup

Before diving into preserving the state, let’s first create a basic TabBar with some tabs. Here's a simple example:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}

class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late TabController _tabController;

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

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TabBar Example'),
bottom: TabBar(
controller: _tabController,
tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.person), text: 'Profile'),
Tab(icon: Icon(Icons.settings), text: 'Settings'),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
HomeTab(),
ProfileTab(),
SettingsTab(),
],
),
);
}
}

In this basic example, we have three tabs: Home, Profile, and Settings. Each tab shows a different widget. However, the state is not preserved when switching between tabs.

2. Add AutomaticKeepAliveClientMixin to Keep Tab State Alive

Now, let’s modify the HomeTab, ProfileTab, and SettingsTab to preserve their state when switching between tabs.

We’ll do this by using AutomaticKeepAliveClientMixin in each of the tab widgets.

Here’s how you can modify one of the tabs (let’s take HomeTab as an example):

class HomeTab extends StatefulWidget {
@override
_HomeTabState createState() => _HomeTabState();
}

class _HomeTabState extends State<HomeTab> with AutomaticKeepAliveClientMixin {
int _counter = 0;

@override
Widget build(BuildContext context) {
super.build(context); // Required to make sure the keep-alive functionality works
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pressed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
ElevatedButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: Text('Increment Counter'),
),
],
),
);
}

@override
bool get wantKeepAlive => true; // Tells Flutter to keep the state alive
}

Breakdown:

  • We extend AutomaticKeepAliveClientMixin to the tab’s state class (_HomeTabState).
  • In the build method, we call super.build(context) to ensure the mixin works properly.
  • Finally, we override the wantKeepAlive getter to return true, telling Flutter to preserve the widget’s state.

3. Repeat for Other Tabs

Now, apply the same changes to the ProfileTab and SettingsTab.

Congrats You’ve Got this !!

4. Done!

That’s it! Now you’ve successfully preserved the state of your tabs in Flutter. Your users can switch between tabs without losing their progress, and you’ve significantly improved the UX of your app.

| Let’s Implement this into our Noted App

1. Implement AutomaticKeepAliveClientMixin in Your Screens

Next, let’s modify our MonthlyScreen and DailyScreen to use AutomaticKeepAliveClientMixin.

MonthlyScreen

Here’s how you can implement it in the MonthlyScreen:

class MonthlyScreen extends StatefulWidget {
@override
_MonthlyScreenState createState() => _MonthlyScreenState();
}

class _MonthlyScreenState extends State<MonthlyScreen> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context); // Need to call super.build for AutomaticKeepAliveClientMixin to work
return Scaffold(
appBar: AppBar(
title: Text('Monthly Tasks'),
),
body: Center(
child: Text('Monthly Tasks Content'),
),
);
}

@override
bool get wantKeepAlive => true; // This ensures the state is preserved
}

DailyScreen

And similarly, for the DailyScreen:

import 'package:flutter/material.dart';

class DailyScreen extends StatefulWidget {
@override
_DailyScreenState createState() => _DailyScreenState();
}

class _DailyScreenState extends State<DailyScreen> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context); // Need to call super.build for AutomaticKeepAliveClientMixin to work
return Scaffold(
appBar: AppBar(
title: Text('Daily Tasks'),
),
body: Center(
child: Text('Daily Tasks Content'),
),
);
}

@override
bool get wantKeepAlive => true; // This ensures the state is preserved
}

2. Explanation

Import Necessary Packages

  • Make sure you have all the necessary packages imported. For MonthlyScreen, we're using fluttertoast, gap, hive_flutter, and some custom packages and models. For DailyScreen, the basic Flutter material package is enough.

Use AutomaticKeepAliveClientMixin

  • We mix in AutomaticKeepAliveClientMixin into our state classes (_MonthlyScreenState and _DailyScreenState). This mixin provides the wantKeepAlive property, which we set to true to preserve the state of these screens.

Call super.build(context)

  • Inside the build method of each screen, we call super.build(context). This is necessary for the mixin to function properly and ensure the state is retained.

| Conclusion

And there you have it! Now your Flutter TabBar won’t reset the state when switching between tabs. This simple trick can enhance your app's performance and keep your users happy by maintaining their data and interactions across tabs.

I hope this helps you in your Flutter journey! If you have any questions or run into any issues, feel free to drop a comment below, and I’ll be happy to help.

Until next time, happy coding! 🚀

| 🚀 Join the Journey!

We’ve built an amazing todo app, “Noted App,” together, but the adventure doesn’t stop here. You can checkout the repository on GitHub and follow along day by day to complete the project with us in this open-source endeavor. đŸŒŸđŸ’»

👉 Explore the GitHub Repository:

Dive into the code, contribute, and collaborate with other developers. Let’s build something great together.

| 🌟 Enjoyed this tutorial?

For more tips, tutorials, and insights into Flutter, be sure to follow my Medium blog! Stay connected, and let’s continue building amazing things together.

This is just Part 28: Ping me on other platforms
 too
.

👉 Follow me:

Happy coding! 🎉 !! Happy Flutter !!

💬 Comment Section is Open!

Share your thoughts or ask questions below.

👏 Applaud if you enjoyed this!

Your claps help others find this content.

➕ Follow for more!

Stay updated with more tips and tutorials.

--

--

Hemant Kumar Prajapati
Hemant Kumar Prajapati

Written by Hemant Kumar Prajapati

Flutter developer đŸŽ©âœš crafting cross-platform apps. Sharing fun coding tips! If you enjoy my guides, Checkout my hopp bio! https://www.hopp.bio/hemant-prajapati