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) );
}
}
Related
I want to show a dialog box as soon as my home screen loads up with the dialog box containing 4 clickable images in a grid view. The images will be routed to individual screens. I am unaware of a way to implement this. Could use some help. Thanks.
You need to use stateful widget to show a dialog when screen loads so do it like this,
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
void initState() {
super.initState();
SchedulerBinding.instance?.addPostFrameCallback((_) {
showDialog(); // your dialong goes here
}
}
}
Note when you are using inistate you don't have access to context so you required use a postFrameCallBack so that whenever context is available the function will get executed.
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;
...
In main, the body of my scaffold is a custom stateful widget. This custom widget has a function inside its state class. Is it possible to call this function from the floating action button in the main file's scaffold?
I don't see how 'wire' the onPressed function of the floating action button to call the function inside the state class of the widget in the scaffold's body.
You can use function callback like this
class Screen extends StatefulWidget {
Screen({Key key}) : super(key: key);
#override
_ScreenState createState() => _ScreenState(methodCaller: myMethod);
String myMethod(int value) {
return 'example';
}
}
class _ScreenState extends State<Screen> {
final String Function(int value) methodCaller;
_ScreenState({this.methodCaller});
#override
Widget build(BuildContext context) {
var value = methodCaller(12);
return Container();
}
}
Hope this is helpful!
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;
}
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())
...
}
}