1

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 Answers3

0

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

vnaren001
  • 244
  • 2
  • 11
  • I tried the globalKey() and passed them into the children but it didn't work ! The post is now updated with snippet code. Thanks in advance! – Christoforos Pantazis Aug 25 '22 at 14:19
  • are you confirmed that Home Widget is new rebuilding again while tab switching, means initState not called for HomeWidget OR try to move the data fecting code from didChangeDependencies to initState under child tab widget class – vnaren001 Aug 26 '22 at 06:35
  • ahh, I check your code again, you are initiating TextEditingController under build method, that is wrong you need to initiate it under initState function or out of build method – vnaren001 Aug 26 '22 at 06:50
0

Please follow the github issue

https://github.com/flutter/flutter/issues/19116

IonicFireBaseApp
  • 925
  • 3
  • 10
0

Add AutomaticKeepAliveClientMixin to each of the Tab widgets.

class _SearchPageState State extends State<SearchPage> with 
AutomaticKeepAliveClientMixin{
}
Muhammad Awais
  • 141
  • 1
  • 5