in flutter when I pass model class in one of the Tab screen I get error in main Bottom Navigation screen - flutter

What I need to pass in BottomNav where I have mentioned all my tabs?
This is More TAB where I want to pass my MODEL class in widget:-
class More extends StatefulWidget{
final UserData currentUser; //UserData is model class
More(this.currentUser,) ;
#override
_MoreState createState() => new _MoreState();
}
And this is BottomNav screen, where I have mentioned all my TAB (I have commented line next to More()where I get error):-
class _BottomNavState extends State<BottomNav> {
int _index = 0;
List<Widget> _items = [
Home(),
UserProfile(FirebaseAuth.instance.currentUser,imageList: [],currentIndex:0),
Notifications(),
Chat(),
More(), /// I get error(red line below More() that I need to pass something here. What is that? So, that I can call my model class in widget.
];
#override
Widget build(BuildContext context) {

You have to provide an UserData to your More stateful widget since you declared that the More widget is expecting a UserData as a parameter
Such as:
final myUserData = UserData();
//...
More(myUserData),

You have defined your constructor like this
More(this.currentUser);
Which makes the currentUser as a mandatory positional parameter at position 0.
So while using your class, you should compulsorily pass an object of UserData like this,
More(UserData());
But in case, it is not mandatory, then you need to change your constructor to this,
More({ this.currentUser });

Related

how to navigate data between two screens in flutter?

I have homeScreen, which every another screen returns to it.
and one of the screens have parameters from TextField, which I need in the homeScreen, how I can navigate these parameters to the home?
NOTE: when I use constructor, the other screens show an error in the line that navigate to Home because there is no parameters.
You can either use an optional parameter in your constructor:
Homepage({String textfield});
and use it on your Homepage (don't forget that this value is nullable)
Or you need to use some kind of state management with ValueNotifiers
You can pass data using parameters
class XYZ extends StatelessWidget {
final TextEditingController textController = TextEditingController();
void navigationFunction() {
//send the data from XYZ to HomePage
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(textValue: textController.text)),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({this.textValue});
final String textValue; //use this textValue in HomePage
#override
Widget build(BuildContext context) {
return Scaffold();
}
}

How to reach a variable of a class from another class in Flutter

I have a stateful widget which includes buttons. I'm keeping number of user taps in an int variable called "counter".
I have another widget which is my home screen. I have a Text on that screen. I need to show the number of taps on this Text dynamically. So when user taps the button on the first class, my Text on the second class must be updated.
What is the best way to pass the counter variable from first widget to second widget?
Added some code
Both of my classes are stateful widgets. So, I declared static int counter like these;
class AppListView extends StatefulWidget {
static int counter;
#override
_AppListViewState createState() => _AppListViewState();
}
Now I can reach counter from other class but can't reach from its own class. I mean I need to increase counter in that part but It says undefined.
class _AppListViewState extends State<AppListView> {
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: (){
counter++ (can't reach counter here)
}
You might want to make your desired variable static.
class Something {
static int counter;
}
Then you can use the variable in the other widget like so:
class StatefulWidget{
FlatButton(
onPressed: (){
Something.counter++; // This variable is your counter you mentioned earlier
}
);
}
Approach 1:
Create a ValueChanged from Parent Widget add pass to FirstWidget, when change couter -> call ValueChanged to send update to Parent Widget, Parent will update state for second Widget.
Approach 2:
Create a Stream from Parent Widget add pass to FirstWidget and Sencond Widget (using StreamBuilder to render widget). when change couter -> change value of Stream to update to Second Widget.
Update Demo:
Link DartPad
Simple, in your code just write "widget.counter" in child. In statefull widget to access parent variable, you have to use "widget.instace". In this case, "widget.counter" will let u access counter variable of the parent.
class AppListView extends StatefulWidget {
int counter;
#override
_AppListViewState createState() => _AppListViewState();
}
class _AppListViewState extends State<AppListView> {
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: (){
widget.counter++
}
Note: u don't need counter variable to be static as u can call it with widget.counter in child class
You should use the provider package to associate the object with Provider, not any widget. Wrap the counter inside a class and pass it to MultiProvider:
void main() {
runApp(
MultiProvider(
providers: [
Provider(create: (context) => Something()),
],
child: const MyApp(),
),
);
}
And then you can access it from your build methods in each widget by:
var something = Provider.of<Something>(context, listen: false);
something.value++;
I suggest one of the existing easy solutions to use a global library to share your application variables between classes :
Create a dart file named globals.dart
globals.dart :
library YOUR_PACKAGE_NAME.globals;
int x = 1 ;
class1 :
import 'package:YOUR_PACKAGE_NAME/globals.dart' as globals;
print(globals.x) ; //prints 1
globals.x= 2 ;
class2 :
import 'package:YOUR_PACKAGE_NAME/globals.dart' as globals;
print(globals.x) ; //prints 2
https://devbrains.tn/forum/question/how-to-call-variables-from-different-class-in-flutter#6

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())
...
}
}

How to pass an object from Stateful Widget to its State? (not in Widget)

I am trying to pass a User object from my stateful widget, to its state.
class NavBar extends StatefulWidget {
final User user;
NavBar({this.user});
#override
NavBarState createState() => NavBarState();
}
class NavBarState extends State<NavBar> {
int _currentIndex = 0;
final List<Widget> _children = [
CalendarWidget(),
HomeWidget(),
MessagingWidget(),
ProfilePage(user: user)
];
Widget build(BuildContext context) {
All other solutions say to use widget.user like ProfilePage(user: widget.user) but that throws error:
Only static members can be accessed in initializers.dart(implicit_this_reference_in_initializer)
How can I access User object in the state of NavBar so I can send it to ProfilePage()?
you can use widget.yourObjectsName to access StateFul widget's Object in its state
you can use any property of Stateful Widgets from its state by widget property of state which gives reference to state's Widget properties.

Controlling State from outside of a StatefulWidget

I'm trying to understand the best practice for controlling a StatefulWidget's state outside of that Widgets State.
I have the following interface defined.
abstract class StartupView {
Stream<String> get onAppSelected;
set showActivity(bool activity);
set message(String message);
}
I would like to create a StatefulWidget StartupPage that implements this interface. I expect the Widget to do the following:
When a button is pressed it would send an event over the onAppSelected stream. A controller would listen to this event and perform some action ( DB call, service request, etc ).
The controller can call showActivity or set message to have the view show progress with a message.
Because a Stateful Widget does not expose its State as a property, I don't know the best approach for accessing and modifying the State's attributes.
The way I would expect to use this would be something like this:
Widget createStartupPage() {
var page = new StartupPage();
page.onAppSelected.listen((app) {
page.showActivity = true;
//Do some work
page.showActivity = false;
});
}
I've thought about instantiating the Widget by passing in the state I want it to return in createState() but that feels wrong.
Some background on why we have this approach: We currently have a Dart web application. For view-controller separation, testability, and forward-thinking towards Flutter, we decided that we would create an interface for every view in our application. This would allow a WebComponent or a Flutter Widget to implement this interface and leave all of the controller logic the same.
There are multiple ways to interact with other stateful widgets.
1. findAncestorStateOfType
The first and most straightforward is through context.findAncestorStateOfType method.
Usually wrapped in a static method of the Stateful subclass like this :
class MyState extends StatefulWidget {
static of(BuildContext context, {bool root = false}) => root
? context.findRootAncestorStateOfType<_MyStateState>()
: context.findAncestorStateOfType<_MyStateState>();
#override
_MyStateState createState() => _MyStateState();
}
class _MyStateState extends State<MyState> {
#override
Widget build(BuildContext context) {
return Container();
}
}
This is how Navigator works for example.
Pro:
Easiest solution
Con:
Tempted to access State properties or manually call setState
Requires to expose State subclass
Don't use this method when you want to access a variable. As your widget may not reload when that variable change.
2. Listenable, Stream and/or InheritedWidget
Sometimes instead of a method, you may want to access some properties. The thing is, you most likely want your widgets to update whenever that value changes over time.
In this situation, dart offer Stream and Sink. And flutter adds on the top of it InheritedWidget and Listenable such as ValueNotifier. They all do relatively the same thing: subscribing to a value change event when coupled with a StreamBuilder/context.dependOnInheritedWidgetOfExactType/AnimatedBuilder.
This is the go-to solution when you want your State to expose some properties. I won't cover all the possibilities but here's a small example using InheritedWidget :
First, we have an InheritedWidget that expose a count :
class Count extends InheritedWidget {
static of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<Count>();
final int count;
Count({Key key, #required Widget child, #required this.count})
: assert(count != null),
super(key: key, child: child);
#override
bool updateShouldNotify(Count oldWidget) {
return this.count != oldWidget.count;
}
}
Then we have our State that instantiate this InheritedWidget
class _MyStateState extends State<MyState> {
int count = 0;
#override
Widget build(BuildContext context) {
return Count(
count: count,
child: Scaffold(
body: CountBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
count++;
});
},
),
),
);
}
}
Finally, we have our CountBody that fetch this exposed count
class CountBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text(Count.of(context).count.toString()),
);
}
}
Pros:
More performant than findAncestorStateOfType
Stream alternative is dart only (works with web) and is strongly integrated in the language (keywords such as await for or async*)
Automic reload of the children when the value change
Cons:
More boilerplate
Stream can be complicated
3. Notifications
Instead of directly calling methods on State, you can send a Notification from your widget. And make State subscribe to these notifications.
An example of Notification would be :
class MyNotification extends Notification {
final String title;
const MyNotification({this.title});
}
To dispatch the notification simply call dispatch(context) on your notification instance and it will bubble up.
MyNotification(title: "Foo")..dispatch(context)
Note: you need put above line of code inside a class, otherwise no context, can NOT call notification.
Any given widget can listen to notifications dispatched by their children using NotificationListener<T> :
class _MyStateState extends State<MyState> {
#override
Widget build(BuildContext context) {
return NotificationListener<MyNotification>(
onNotification: onTitlePush,
child: Container(),
);
}
bool onTitlePush(MyNotification notification) {
print("New item ${notification.title}");
// true meaning processed, no following notification bubbling.
return true;
}
}
An example would be Scrollable, which can dispatch ScrollNotification including start/end/overscroll. Then used by Scrollbar to know scroll information without having access to ScrollController
Pros:
Cool reactive API. We don't directly do stuff on State. It's State that subscribes to events triggered by its children
More than one widget can subscribe to that same notification
Prevents children from accessing unwanted State properties
Cons:
May not fit your use-case
Requires more boilerplate
You can expose the state's widget with a static method, a few of the flutter examples do it this way and I've started using it as well:
class StartupPage extends StatefulWidget {
static StartupPageState of(BuildContext context) => context.ancestorStateOfType(const TypeMatcher<StartupPageState>());
#override
StartupPageState createState() => new StartupPageState();
}
class StartupPageState extends State<StartupPage> {
...
}
You can then access the state by calling StartupPage.of(context).doSomething();.
The caveat here is that you need to have a BuildContext with that page somewhere in its tree.
There is another common used approach to have access to State's properties/methods:
class StartupPage extends StatefulWidget {
StartupPage({Key key}) : super(key: key);
#override
StartupPageState createState() => StartupPageState();
}
// Make class public!
class StartupPageState extends State<StartupPage> {
int someStateProperty;
void someStateMethod() {}
}
// Somewhere where inside class where `StartupPage` will be used
final startupPageKey = GlobalKey<StartupPageState>();
// Somewhere where the `StartupPage` will be opened
final startupPage = StartupPage(key: startupPageKey);
Navigator.push(context, MaterialPageRoute(builder: (_) => startupPage);
// Somewhere where you need have access to state
startupPageKey.currentState.someStateProperty = 1;
startupPageKey.currentState.someStateMethod();
I do:
class StartupPage extends StatefulWidget {
StartupPageState state;
#override
StartupPageState createState() {
this.state = new StartupPageState();
return this.state;
}
}
class DetectedAnimationState extends State<DetectedAnimation> {
And outside just startupPage.state
While trying to solve a similar problem, I discovered that ancestorStateOfType() and TypeMatcher have been deprecated. Instead, one has to use findAncestorStateOfType(). However as per the documentation, "calling this method is relatively expensive". The documentation for the findAncestorStateOfType() method can be found here.
In any case, to use findAncestorStateOfType(), the following can be implemented (this is a modification of the correct answer using the findAncestorStateOfType() method):
class StartupPage extends StatefulWidget {
static _StartupPageState of(BuildContext context) => context.findAncestorStateOfType<_StartupPageState>();
#override
_StartupPageState createState() => new _StartupPageState();
}
class _StartupPageState extends State<StartupPage> {
...
}
The state can be accessed in the same way as described in the correct answer (using StartupPage.of(context).yourFunction()). I wanted to update the post with the new method.
You can use eventify
This library provide mechanism to register for event notifications with emitter
or publisher and get notified in the event of an event.
You can do something like:
// Import the library
import 'package:eventify/eventify.dart';
final EventEmitter emitter = new EventEmitter();
var controlNumber = 50;
List<Widget> buttonsGenerator() {
final List<Widget> buttons = new List<Widget>();
for (var i = 0; i < controlNumber; i++) {
widgets.add(new MaterialButton(
// Generate 10 Buttons afterwards
onPressed: () {
controlNumber = 10;
emitter.emit("updateButtonsList", null, "");
},
);
}
}
class AState extends State<ofYourWidget> {
#override
Widget build(BuildContext context) {
List<Widget> buttons_list = buttonsGenerator();
emitter.on('updateButtonsList', null, (event, event_context) {
setState(() {
buttons_list = buttonsGenerator();
});
});
}
...
}
I can't think of anything which can't be achieved by event driven programming. You are limitless!
"Freedom cannot be bestowed — it must be achieved."
- Elbert Hubbard
Have you considered lifting the state to the parent widget? It is a common, though less ideal than Redux, way to manage state in React as far as I know, and this repository shows how to apply the concept to a Flutter app.