I am learning flutter right now and I am reading some tutorial code. I know angle brackets e.g. refer to a set of widgets but how I should understand follow code then:
return Center(
child: ChangeNotifierProvider<CartModel>(
data: CartModel(),
child: Builder(builder: (context) {...}
This is a set of CartModel? but then what does the ChangeNotifierProvider mean here?
The ChangeNotifierProvider is there to listen to the notifications of the CartModel Provider.
The CartModel is the type of provider that the ChangeNotifierProvider will listen to for updates.
ChangeNotifierProvider is the constructor with the argument.
data: CartModel(),
child: Builder(builder: (context) {...}
which will call the build method of class ChangeNotifierProvider.
Related
I've read the flutter-bloc documentation and I really have no idea what to do anymore. Someone to help?
error bloc provider
Probably you didn't import the Bloc package into this file.
Try create: instead of bloc:
BlocProvider<UserBloc>(
create: (context) => UserBloc(),
child: Container(),
);
Firstly, I am sorry for my poor english.
I am trying success to extract a very complex widget as package and use it on different projects. For this reason, I need to use ScreenUtil package (for responsive design.) in that widget-package.
So in the end, I succeed the extract my widget as a package but I am confused some point because as you know, screen_util package requires to be initialized like;
ScreenUtilInit(
designSize: const Size(750, 1334),
builder: () => const MyApp(),
)
So my question, how can I success to initialize the screen_util package correctly for my usage ? (I don't have any builder function because my widgets created like class MyWidget extends SizedBox(important not like stateless or statefull widget!)) so,
I added a function for initializing operation like ;
void myComponentInitializer({
required BuildContext context
}){
ScreenUtil.init(
BoxConstraints(
maxWidth: MediaQuery.of(context).size.width,
maxHeight: MediaQuery.of(context).size.height
),
context: context,
designSize: const Size(750, 1334),
minTextAdapt: true
);
ScreenUtil.setContext(context);
}
and before using the package, I am calling that function but I can't be sure, is it a best way to initialize screen_util for my widget or not. If it is not the right way, can you show me the right way ?
So I am open any idea for this.
Thanks a lot.
You just initialise your screen utils on your first page/screen or your initial route. You can initialise it inside your init() method of your stateful widget or initialise it inside your build() function of your stateless widget. Hope this is clear.
I think that the builder Generally returning a Function of MaterialApp type,
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 690),
minTextAdapt: true,
splitScreenMode: true,
builder: () =>
MaterialApp()
Docs link
how can I dispose ChangeNotifierProvider.value( ) in Flutter
so there will be no memory leaks
I made the object that is as a value to the ChangeNotifierProvider.value( ) as a singleton
cause I need more than page to share their state in one object
ChangeNotifierProvider automatically calls the dispose() method of the state when it is needed. You need not do anything about that. They talk about this in this video:Pragmatic State Management in Flutter (Google I/O'19)
You need to use the dispose() method of State or the default constructor of ChangeNotifierProvider. The latter automatically disposes of the object created in the create function.
I wonder why you are using ChangeNotifierProvider.value() instead of ChangeNotifierProvider(), but assuming you want to pass the value to a different page, you can combine both as follows.
ChangeNotifierProvider<Foo>(
create: (context) => Foo(), // this Foo object is disposed of automatically
)
Somewhere down the tree:
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context2) => Provider<Foo>.value(
value: Provider.of<Foo>(context, listen: false),
child: NextPage(),
),
),
)
Note: You won't have to do this if you provide the value from above MaterialApp.
This is my code
Widget homeDashBoardCards(title, image, BuildContext context) {
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DashBoardScreen(),
),
),
);
}
and I need to just be able to change this context to chose the page, instead of creating a lot of Widgets.
homeDashBoardCards('Categories', 'chii-icon.png', context),
like creating 2 cases or more in this one...
builder: (context) => DashBoardScreen
Just as an example:
builder: (context) => case "1" = DashBoardScreen
case "2" = FavoriteScreen
Thank you guys...
1. What I think the Problem Is
What you want is not 100% clear from the question, but I think you simply want a function that would have a switch inside returning which page the user should go to?
In that case, you might want to check out:
Flutter's tutorials on routing
switch statement in Dart
2. One Possible Solution
Create a switch function for deciding which page to switch to. Instead of using Strings, I highly suggest using enums. But both are possible.
enum Screens {dashboard, favorite}
Widget screenSwitcher(Screens screenEnum) {
switch (screenEnum) {
case Screens.dashboard:
return DashBoardScreen();
case Screens.favorite:
return FavoriteScreen();
default:
throw Exception;
}
}
Note that, if you have a non-empty case clause ending with a return, throw or continue, you don't need a break. The default clause doesn't need a break.
Return the screen when routing by calling the switcher function — you can obviously create more parameters for the functions, if necessary —:
Widget homeDashBoardCards(title, image, Screens screenEnum, BuildContext context) {
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => screenSwitcher(screenEnum),
),
),
);
}
3. Further Reading
Your code will be much simpler and easier to read if you use Named Routing, as mentioned in the first section of this answer. Additionally, if routing is very important to your app and complicated, you might want to consider looking for or creating a package in the pub.dev package host.
If you accept the solution code I shared above, you're passing variables through different widgets, which is not very object-oriented and also not the Flutter way. You should then consider state sharing packages to work around that. Two of the most notable ones are the BLoC and the Provider packages, but you can also do it with rxdart and the get_it package, check this video by Fireship for a great summary.
I have a MainBloc that resides inside a main route, this route has a bottom app bar with multiple sub-routes, I want the same BLoC to run on all five sub-routes so that when one of them changes the state of the block the others will see the effect.
I tried this SO question but its really far from what I'm looking for, also I tried following what the error advised me to, but didn't work, here is the message that I got:
This can happen if:
1. The context you used comes from a widget above the BlocProvider.
2. You used MultiBlocProvider and didn't explicity provide the BlocProvider types.
Good: BlocProvider<MainBloc>(builder: (context) => MainBloc())
Bad: BlocProvider(builder: (context) => MainBloc()).
Main route:
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<MainBloc>(
builder: (BuildContext context) => MainBloc(),
),
BlocProvider<OtherBloc>(
builder: (BuildContext context) => OtherBloc(),
),
],
child: /..., //here I have the bottom app bar with 5 buttons to navigate between sub-routes
);
one of the sub-routes:
#override
Widget build(BuildContext context) {
final MainBloc bloc = BlocProvider.of<MainBloc>(context);
return /...; //here I have the context of this sub-route.
}
from what I've seen from tutorials and articles this code should work, but I can't seem to find why not.
The problem is you cannot access InheritedWidgets across routes unless you provide the InheritedWidget above MaterialApp. I would recommend wrapping your new route in BlocProvider.value to provide the existing bloc to the new route like:
Navigator.of(context).push(
MaterialPageRoute<MyPage>(
builder: (_) {
return BlocProvider.value(
value: BlocProvider.of<MyBloc>(context),
child: MyPage(),
);
},
),
);
You can find more detailed information about this in the bloc documentation
As this child has the bottom app bar:
child: /..., //here I have the bottom app bar
then I assume that the MultiBlocProvider(..) is not wrapping the whole part of app which is using this Bloc, my suggestion here is to wrap the "MaterialApp" with "MultiBlocProvider".
return MultiBlocProvider(
providers: [..],
child: MaterialApp(..) // Set MaterialApp as the child of the MultiBlocProvider
//..
)