How to rebuild the root widget of flutter? - flutter

I am using provider package to detect changes in 'todaysTasks' but as you can see 'todayTasks' depends on DaysRecords which stores a list of DayTasks, so what I want is to rebuild my root widget (which is MyApp) whenever i push a DayTask in DaysRecords.recordsList but can't figure out any way to do that.
Is there any solution to this??
class MyApp extends StatelessWidget {
static const routeName = '/root';
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
DayTasks todaysTasks = DaysRecords.recordsList.last;
return ChangeNotifierProvider(
create: (context) => todaysTasks,

You can just wrap the parent widget of MyApp (I'm guessing, it is MaterialApp on main method) with ChangeNotifierProvider instead of wrapping inside MyApp.
Then initialize the correspondent provider in MyApp's build method or use a consumer to rebuild (manage your state).
void main() {
runApp(MaterialApp(
home: RootWidget(),
));
}
class RootWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => SomeProvider(),
child: MyApp(),
);
}
}
class MyApp extends StatelessWidget {
static const routeName = '/root';
#override
Widget build(BuildContext context) {
final provider = Provider.of<SomeProvider>(context, listen: true);
// DayTasks todaysTasks = provider.recordsList.last;
return Scaffold(
body: AppBar(
automaticallyImplyLeading: false,
),
);
}
}

Related

Why ChangeNotifierProvider disappears from Widget Tree when using routes?

I'm having trouble understanding this: When the ChangeNotifierProvider widget is below the MaterialApp one in the widget tree, it disappear from the widget tree when I use the Navigator.of(context).pushReplacement method to go to the next screen. However, when the ChangeNotifierProvider widget is above the MaterialApp one in the widget tree, it stays in the widget tree.
Here is a simple example below.
ChangeNotifierProvider widget that disappear example:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp( <= DIFFERENCE HERE
title: 'Flutter Demo',
home: ChangeNotifierProvider(
create: (context) => ToiletsListModel(), child: SplashWidget()));
}
}
class SplashWidget extends StatefulWidget {
SplashWidget();
#override
State<SplashWidget> createState() => SplashWidgetState();
}
class SplashWidgetState extends State<SplashWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ElevatedButton(
child: Text("press"),
onPressed: goNext,
),
);
}
goNext() async {
await Future.delayed(Duration(seconds: 3));
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) => HomeScreen()));
}
}
#override
void initState() {
super.initState();
[1, 2, 3, 4, 5].forEach((t) {
Provider.of<MyModel>(context, listen: false).mylist.add(t);
});
print(Provider.of<MyModel>(context, listen: false).mylist);
}
}
The widget tree:
ChangeNotifierProvider widget that stays example:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider( <= DIFFERENCE HERE
create: (context) => ToiletsListModel(),
child: MaterialApp(title: 'Flutter Demo', home: SplashWidget()));
}
}
class SplashWidget extends StatefulWidget {
SplashWidget();
#override
State<SplashWidget> createState() => SplashWidgetState();
}
class SplashWidgetState extends State<SplashWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ElevatedButton(
child: Text("press"),
onPressed: goNext,
),
);
}
goNext() async {
await Future.delayed(Duration(seconds: 3));
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) => HomeScreen()));
}
}
#override
void initState() {
super.initState();
[1, 2, 3, 4, 5].forEach((t) {
Provider.of<MyModel>(context, listen: false).mylist.add(t);
});
print(Provider.of<MyModel>(context, listen: false).mylist);
}
}
The widget tree:
It makes me crazy and I can't find any answer. I suppose that pushReplacement() does something to the widget tree or that ChangeNotifierProvider is not persistent (altough I did not see that in the documentation, i'm not even sure it's possible tbh). Also, I read that using the ChangeNotifierProvider above the MaterialApp wasn't a good idea but I don't know why.
Thanks for your help.

Keep Widget always visible while changing pages in flutter

I'm currently using Navigator.pushNamed for changing the content of my app and I would like to have a persistent widget on top of every page without loading it every time I change a page. Is it possible or I have to change my entire app to use one scaffold and update the content of the scaffold? I would like to avoid this solution.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Page1(),
builder: (context, child) {
return Scaffold(
appBar: AppBar(), // the common thing.
body: child,
);
},
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();// add button to go to Page2
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
Description:
builder allows you to pass the different widget and each widget will be wrapped with the common widget, AppBar inside the scaffold here. Thus the scaffold and appbar is common for each page you visit.

MediaQuery.of() called with a context that does not contain a media query. visual studio Code [duplicate]

I have been trying to get the size of the whole context view in Flutter. But every time I try I'm getting the above mentioned error.
Here's my code:
import 'package:flutter/material.dart';
void main => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return new MaterialApp(
home: new Scaffold(),
);
}
}
Note: I also tried with a StatefulWidget.
Please, help me find what I'm doing wrong here.
You need a MaterialApp or a WidgetsApp around your widget. They provide the MediaQuery. When you call .of(context) flutter will always look up the widget tree to find the widget.
You usually have this in your main.dart:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title',
theme: kThemeData,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Container(
child: ...,
);
}
}
What works for us is using WidgetsBinding.instance.window instead of MediaQuery - also when setting the theme of the MaterialApp:
_pixelRatio = WidgetsBinding.instance.window.devicePixelRatio;
_screenWidth = WidgetsBinding.instance.window.physicalSize.width;
_screenHeight = WidgetsBinding.instance.window.physicalSize.height;
_statusBarHeight = WidgetsBinding.instance.window.padding.top;
_bottomBarHeight = WidgetsBinding.instance.window.padding.bottom;
_textScaleFactor = WidgetsBinding.instance.window.textScaleFactor;
You can access MediaQuery when you are inside MaterialApp. The place where you are accessing the media query is not correct.
Please refer below code:
import 'package:flutter/material.dart';
class CommonThings {
static Size size;
}
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'MediaQuery Demo',
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
CommonThings.size = MediaQuery.of(context).size;
print('Width of the screen: ${CommonThings.size.width}');
return new Container();
}
}
I've purposely created a class CommonThings which has static Size so that you can use it throughout the app.
I fixed it by using the following method. First I created a new class named MyWidget and returned it in MyApp within a MaterialApp's home:. Refer code below:
import 'package:flutter/material.dart';
void main => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyWidget(),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return new MaterialApp(
home: new Scaffold(),
);
}
}
Also, declaring size as final doesn't matter. Orientation/Rotation is handled.
Solved by re-run the app(click on stop button in android studio then run again)
There is better way. Above solutions would require you to have only one screen widget or inherit all screens from parent class. But there is solution, place the media query initialization into onGenerateRoute callback function
main.dart
import 'package:flutter/material.dart';
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Awesome App',
routes: NavigationUtils.routeList(),
onGenerateRoute: (routeSettings) =>
NavigationUtils.onGenerateRoute(routeSettings),
);
}
}
NavigationUtils.dart
import 'package:flutter/material.dart';
class NavigationUtils {
static onGenerateRoute(RouteSettings routeSettings) {
return new MaterialPageRoute(
builder: (context) {
WidgetUtils.me.init(context);
return StorageUtils.me.isLogged() ? HomeScreen() : ForkScreen();
},
settings: routeSettings,
);
}
}
WidgetUtils.dart
import 'package:flutter/material.dart';
class WidgetUtils {
MediaQueryData _mediaQueryData;
double _screenWidth;
double _screenHeight;
double _blockSizeHorizontal;
double _blockSizeVertical;
init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
blockSizeHorizontal = screenWidth / 100;
blockSizeVertical = screenHeight / 100;
}
}
Warning: It is not copy & paste code, there are some singletons etc. but you should get the point ;)
Had the same error in
import 'screens/tasks_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TasksScreen();
}
}
I solved it by:-
import 'package:flutter/material.dart';
import 'screens/tasks_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: TasksScreen(),
);
}
}
Wrap your code in a Material App widget. I also had the same issue as I forgot to use it and directly returned the scaffold.
In other words, your MediaQuery.of(context) should be inside the Material Widget.
Material app -> scaffold -> MediaQuery.of(context)
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyAppOne(),
);
}
}
class MyAppOne extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyAppOne>{
#override
Widget build(BuildContext context){
return Scaffold(
);
}
}
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size.height;
return Container(
height:size/2,
color:Colors.lightBlueAccent,
);
}
}
YOU SHOULD TRY THIS I HAVE DONE IT.
I was trying to change the package then this error arise,
so make sure you complete each of the following steps
https://stackoverflow.com/a/51550358/4993045
Add MaterialApp ...
void main() {
runApp(MaterialApp(
home: HomePage(),
));
}

How to call a Stateless widget in MyApp's build method whose state is managed by its Stateful Parent

I was following flutter tutorials for managing state of a widget from its parent on this link [https://flutter.dev/docs/development/ui/interactive#parent-managed][1]
and i cant figure out how would call the widget in this case
it is very simple once you get the logic.
In practice, the parent (the "true" widget that you call), i.e.
class ParentWidget extends StatefulWidget {
#override
_ParentWidgetState createState() => _ParentWidgetState();
}
is the one that you call wherever and whenever you want in the rest of the code.
Since this is a Stateful widget, it means that it has stated (to keep it simple, it will manage any changes on the UI). Any change will occur, It will be changing its state and so, this code:
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
#override
Widget build(BuildContext context) {
return Container(
child: TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
Anyhow, once you use a Stateful widget, you change its state whenever you want to call the function
setState(() {
oldValue= newValue;
});
It will rebuild the entire widget changing the stuff you want (such as texts, images, widgets, and so on).
In a non-proper way, consider it as a particular widget that can change its UI during the time.
if you want to call it in MyApp's build method you will have to make MyApp a stateful widget so that it can manage the state of the said widget
void main() => runApp(MyApp());
//we make MyApp to be a stateful widget
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
//we define the state which will be used in the widget here
var myState = "something";
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Container(
//the data used by MyWidget is managed by MyApp which is a statefull widget.
child: MyWidget(state: myState),
),
),
),
);
}
}
Or rather wrap your widget with another stateful widget which you will use in MyApp's build method
//we create a widget which will manage the state of its children class MyStateManagingWidget extends StatefulWidget { #override
_MyStateManagingWidgetState createState() => _MyStateManagingWidgetState(); }
class _MyStateManagingWidgetState extends State<MyStateManagingWidget> { var myState = "some state"; #override Widget build(BuildContext context) {
//we put our widget who's state is to be managed here
return MyWidget(); } }
class MyApp extends StatelessWidget { #override Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Container(
//we now use the state managing widget here
child: MyStateManagingWidget()),
),
),
); } }

Navigate between pages using Navigator issue

I am studying Flutter and building my first app using this framework.
Now I am facing a problem.
My scenario is very simple I want to navigate from the main screen to another screen.
this is the code of the from the home view
class HomeView extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return HomeViewState();
}
}
class HomeViewState extends State<HomeView> {
...
and I want to navigate to to another screen using Navigator
#override
Widget build(BuildContext context) {
return Container(
child: InkWell(
onTap: () {
Navigator.of(context).pushNamed('/userdetailsview');
},
child: Card(
...
this is my App.Dart
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
home: Scaffold(
body: Center(
child: HomeView(),
),
),
routes: <String,WidgetBuilder>{
'/homeview': (BuildContext context) => new HomeView(),
'/userdetailsview': (BuildContext context) => new UserDetails(),
},
);
}
}
finally this is the code for the page I want to navigate
class UserDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Text('test');
}
}
As you can see my scenario is very simple but this is the result .
As you can see for some reason the second page is overlapping the main page.
I am developer using Xamarin Forms and XAML applications Flutter is very easy to understand and I really like it but there is a lack of information about simple task like this one.
I would appreciate if someone could help to fix my issue
Thank you!.
Try this in UserDetails.dart
class UserDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: Text('test');
)
}
}