How do I preserve the data in my textfield when navigating to another tabview - flutter

How do I preserve my data when I navigate between two different tabs in Flutter... Basically what I want to achieve is, on one side of the tab, I see users data, and on the other side of the tab, I want to be able to copy some of those user data and paste into some textfields on the other tab without losing the data in the text fields when I navigate back and forth and still also preserving the level of scrolling I might have done on the tab where the users data show.

You need to use AutomaticKeepAliveClientMixin This will ensure the State instance is not destroyed when leaving the screen.Extend your every tabview's state class with it and create an override method wannaKeepAlive and set it to true.Here is an example of a widget using AutomaticKeepAliveClientMixin.
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return Container(
);
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

Related

Flutter hive clearing box during swiping between tabs

In my case we have 3 tabs in TabController and in all of this pages we have some data which we want to use them, now on each tab when we are swiping between them we don't have previous data and length of box values is 0, you suppose we have three tab as:
screen_a
screen_b
screen_c
into screen_a we have:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() =>MyHome();
}
class MyHome extends State<Home> {
late Box<Level> _level;
late List<Level> levels ;
late VideoPlayerController _controller;
#override
void initState() {
super.initState();
_level = Hive.box<Level>('level');
levels = _level.values.toList();
}
#override
Widget build(BuildContext context) {
now on starting application we have many data on screen_a and after swiping on screen_b and going back to screen_a we don't have any data in hive :| :|
what's the problem?
You should store your tabs' data in a bloc or controller class that does not lose state and data when switching between tabs.
It depends on your overall use case and how you want your TabViews to behave, but you can work with the AutomaticKeepAliveClientMixin to ensure that your state of the StatefulWidget stays intact when switching tabs. This also ensures that the content of your StatefulWidget does not have to be rebuild when switching tabs, but will still use resources (just to keep in mind for performance considerations when working with more complex scenarios):
class MyHome extends State<Home> with AutomaticKeepAliveClientMixin {
/// Here you can either add custom logic to determine when
/// this tab should be kept "alive" - for now returning [true]
/// will work out.
#override
bool get wantKeepAlive => true;
...

Change loaded Widget outside of Main file (setState not available)

I have a MainScreen() file where I defined two Widgets, side by side:
Left menu (ListTiles).
Main View (rest of screen, to the right).
My issue is that I need to tap the ListTiles on the left and dynamically change the Widget loaded on the Main View.
Any suggestions?
The main view must be stateful for this to work, as you need to trigger a rerender once you tap one of the tiles. You want to pass a callback function from your main screen to your menu of list tiles.
Your best bet is to setup an enum and have each listtile provide the callback with its own enum value.
Once you have the callback in your list of tiles, you can easily pass it onward to the individual tiles. Then, execute the callback function onTap and provide it with the correct enum value.
On your main screen, you just show the correct widget by looking at the current enum value.
class MainScreen extends StatefulWidget {
const MainScreen({Key? key}) : super(key: key);
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
MyEnum _currentTile = MyEnum.Home;
void _callbackFunction(MyEnum tileOption) {
setState(() {
_currentTile = tileOption;
});
}
#override
Widget build(BuildContext context) {
return MyCustomListTile((MyEnum tile) => _callbackFunction(tile) );
}
}

How to keep checkbox state while browsing between navigation bar items

In Flutter, I have a bottom navigator bar and there are 4 different bottom navigator bar items in it. In the 4th menu item, I have a checkbox widget. While browsing in the navigation bar items I would like the checked or unchecked items situation remains. For example if I uncheck this widget I would like it to stay still "unchecked" while browsing in other navigation bar items. How can I do this? I tried to use key parameter of checkbox but I failed.
You should use AutomaticKeepAliveClientMixin
to keep state Alive while you browse between your items.Extend your state class with it and create an override method wannaKeepAlive and set it to true.Here is an example of a widget using AutomaticKeepAliveClientMixin.
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return Container(
);
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
Welcome to State management!
Official guideline for state management from Flutter team.
I would recommend to read everything starting from introduction to state management.

Flutter: How can I avoid recreating the model for parts of the application?

My app uses a set of Card()s inside a PageView(), each card has multiple text lines.
The user gives input for each line (e.g. modifying the text etc.).
I want to keep this input for a while.
This is how my code looks at the moment, abstractly speaking:
class MyCard extends StatefulWidget {
final List<Widget> _myLines = [];
#override
State<StatefulWidget> createState() => MyCardState();
}
class MyCardState extends State<MyCard> {
...
#override
Widget build(BuildContext context) {
...
widget._myLines.add(ChangeNotifierProvider(
create: (context) => MyLineModel(context, lineText),
child: RecipeLine())
...
}
}
This doesn't work well:
As soon as I swipe left / right through the PageView onto other cards and then swipe back, the Card is being built again. This also leads to a rebuild of MyLineModel, which in turn erases all the user's input.
How can I avoid the rebuild of MyLineModel and keep the user's input?
You can solve this in 2 ways:
Create the model outside the widget and pass the model for the widget, as a variable to a constructor for example, or using Provider or any other technique of Dependency Injection.
Using any of the KeepAlive APIs, such as the AutomaticKeepAliveClientMixin as:
class MyCardState extends State<MyCard> with AutomaticKeepAliveClientMixin {
...
#override
bool get wantKeepAlive => true;
}
As the official documentation states, we can simply use the ChangeNotifierProvider.value() constructor...
In the original code:
class MyCardState extends State<MyCard> {
...
#override
Widget build(BuildContext context) {
...
widget._myLines.add(ChangeNotifierProvider.value(
value: MyLineModel(context, lineText),
child: RecipeLine())
...
}
}

Why build method isn't defined inside StatefulWidget?

I'm currently learning Flutter. I tried to deep dive into Flutter Widget life-cycle, and I wonder why StatefulWidget are written like this :
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
but not :
class Example extends StatefulWidget {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
I think the latter makes the source simple. But I don't know why they're using the former style ?
The reason why StatefulWidget uses a separate State class and not having build method inside its body is because all fields inside a Widget are immutable, and this includes all its sub-classes.
You might have noticed that StatelessWidget has its build and other associated methods defined inside it, but that was possible due to the nature of StatelessWidget which is rendered completely using the provided info, and doesn't expect any future change in its State.
In the case of StatefulWidget, State information occasionally change (or expected to change) during the course of the app, thus this information isn't suitable for storage in a final field (build) to satisfy Widget class conditions (all fields are immutable). That's why State class is introduced. You just have to override the createState function to attach your defined State to your StatefulWidget, and let all that change happens in a separate class.