skip to Main Content

I am currently developing a flutter desktop CRM and I want to implement a multi tab feature. But when I change into another tab and then back to the first flutter rebuild the whole widget. So when write some data to the text input inside tab "Tab appointmentsKey"(Image 1) and then I change into another tab(Image 2) and then back to tab "Tab appointmentsKey", my data is lost(Image 3).

I am using fluent UI Library link for the Tab Widget ( TabView Widget )

Question:
Is there a way to ignore rebuild when I change between the tabs?

Here my $flutter doctor:

[√] Flutter (Channel stable, 3.0.5, on Microsoft Windows [Version 10.0.19044.1889], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.2.6)   
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.70.2)
[√] VS Code, 64-bit edition (version 1.20.1)
[√] Connected device (3 available)
[√] HTTP Host Availability

Here my $flutter --version:

Flutter 3.0.5 • channel stable • https://github.com/flutter/flutter.git  
Framework • revision f1875d570e (6 weeks ago) • 2022-07-13 11:24:16 -0700
Engine • revision e85ea0e79c
Tools • Dart 2.17.6 • DevTools 2.12.2

Here snippets:

home.dart (host of the tabView widget ):

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

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home>{
  //TODO replace isLoaded with false
  bool isLoaded = true;
  bool serverProblem = false;

  int currentIndex = 0;

  final AppointmentGlobalKey = GlobalKey();
  final DashboardGlobalKey = GlobalKey();

  late Map<String, Map<String, dynamic>> mapScreenRoutes;

  @override
  void initState() {
    mapScreenRoutes = {
      App.appointmentsKey: {
        "title": "Appointments",
        "screen": AppointmentsScreen(),
      },
      App.dashboardKey: {
        "title": "Dashboard",
        "screen": DashBoardScreen(),
      },
    };

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return isLoaded == false
        ? LoadingScreen(serverProblem: serverProblem)
        : Scaffold(
            body: Row(
              children: [
                const SizedBox(
                  width: 260,
                  height: double.infinity,
                  child: VerticalNavBar(),
                ),
                Expanded(
                  child: Column(
                    children: [
                      const HeaderSearchAccount(),
                      Expanded(
                        child: SizedBox(
                          child: fui.TabView(
                              closeButtonVisibility:
                                  fui.CloseButtonVisibilityMode.always,
                              currentIndex: currentIndex,
                              onChanged: (index) => setState(() {
                                    currentIndex = index;
                                  }),
                              onNewPressed: null,
                              tabs: [
                                fui.Tab(
                                  text: Text(
                                      mapScreenRoutes[App.appointmentsKey]
                                          ?['title']),
                                  closeIcon: fui.FluentIcons.chrome_close,
                                ),
                                fui.Tab(
                                  text: Text(mapScreenRoutes[App.dashboardKey]
                                      ?['title']),
                                  closeIcon: fui.FluentIcons.chrome_close,
                                )
                              ],
                              bodies: [
                                AppointmentsScreen(
                                  key: AppointmentGlobalKey,
                                ),
                                DashBoardScreen(
                                  key: DashboardGlobalKey,
                                ),
                              ]),
                        ),
                      ),
                    ],
                  ),
                )
              ],
            ),
          );
  }
}

And the two Widget that are inside in each tab body:

appointments_screen.dart:

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

  @override
  State<AppointmentsScreen> createState() => _AppointmentsScreenState();
}

class _AppointmentsScreenState extends State<AppointmentsScreen> {
  bool isLoaded = false;
  bool serverProblem = false;

  @override
  void didChangeDependencies() {
    Api.get().fetchTextTest().then((value) {
      print(value);

      setState(() {
        isLoaded = true;
      });
    });

    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    final emailController = TextEditingController();

    final formKey = GlobalKey<FormState>();
    return isLoaded == false
        ? LoadingScreen(serverProblem: serverProblem)
        : Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text('Appointments()'),
              Center(
                child: Form(
                  key: formKey,
                  child: TextFormField(
                    keyboardType: TextInputType.emailAddress,
                    controller: emailController,
                    autofocus: false,
                    decoration: InputDecoration(
                      hintText: 'Email',
                      contentPadding:
                          EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
                      border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(32.0)),
                    ),
                  ),
                ),
              ),
            ],
          );
  }
}

dashboard_screen.dart:

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

  @override
  State<DashBoardScreen> createState() => _DashBoardScreenState();
}

class _DashBoardScreenState extends State<DashBoardScreen>
    with AutomaticKeepAliveClientMixin {
  //TODO replace isLoaded with false
  bool isLoaded = true;
  bool serverProblem = false;

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

  @override
  bool get wantKeepAlive => true;
  @override
  Widget build(BuildContext context) {
    return isLoaded == false
        ? LoadingScreen(serverProblem: serverProblem)
        : Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: const [
              Text('DashBoardScreen()'),
            ],
          );
  }
}

3

Answers


  1. No exact idea about the library you mentioned.
    But if possible you can define Key for your children’s tabs views, so that it will keep the state, and you can avoid rebuild of widgets.

    example:
    final childKeyTab1 = GlobalKey();
    YourCustomStateFullWidget(key: childKeyTab1);

    Update:
    I checked your code again, you are initiating TextEditingController under the build method, that is wrong you need to initiate it under initState function or out of the build method

    Login or Signup to reply.
  2. Add AutomaticKeepAliveClientMixin to each of the Tab widgets.

    class _SearchPageState State extends State<SearchPage> with 
    AutomaticKeepAliveClientMixin{
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search