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()'),
],
);
}
}
CodePudding user response:
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);
CodePudding user response:
Please follow the github issue
https://github.com/flutter/flutter/issues/19116
CodePudding user response:
Add AutomaticKeepAliveClientMixin to each of the Tab widgets.
class _SearchPageState State extends State<SearchPage> with
AutomaticKeepAliveClientMixin{
}