to make it simple , I'm creating a dashboard where I have a Drawer on the left side of the screen and Another widget that will change based on what the user will choose from Drawer.
Anyway , After adding the onPressed for a menu item , when I press to re-call a new widget next to the drawer I'm getting this error :
Could not find the correct provider<MenuController$> above MainScreen Widget.
So first this is my main.dart :
import 'package:admin/constants.dart';
import 'package:admin/controllers/MenuController.dart';
import 'package:admin/screens/dashboard/dashboard_screen.dart';
import 'package:admin/screens/main/main_screen.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Admin Panel',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: bgColor,
textTheme: GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme)
.apply(bodyColor: Colors.white),
canvasColor: secondaryColor,
),
home: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MenuController(),
),
],
child: MainScreen(DashboardScreen()),,
),
);
}
}
and this is my MenuController :
import 'package:flutter/material.dart';
class MenuController extends ChangeNotifier {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
GlobalKey<ScaffoldState> get scaffoldKey => _scaffoldKey;
void controlMenu() {
if (!_scaffoldKey.currentState.isDrawerOpen) {
_scaffoldKey.currentState.openDrawer();
}
}
}
and this is my main_screen :
import 'package:admin/controllers/MenuController.dart';
import 'package:admin/responsive.dart';
import 'package:admin/screens/dashboard/dashboard_screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'components/side_menu.dart';
class MainScreen extends StatefulWidget {
Widget newWidget;
MainScreen(this.newWidget);
#override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
key: context.read<MenuController>().scaffoldKey,
drawer: SideMenu(),
body: SafeArea(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// We want this side menu only for large screen
if (Responsive.isDesktop(context))
Expanded(
// default flex = 1
// and it takes 1/6 part of the screen
child: SideMenu(),
),
Expanded(
// It takes 5/6 part of the screen
flex: 5,
child: DashboardScreen(),
),
],
),
),
);
}
}
and finally this is my side_menu :
DrawerListTile(
title: "Fournisseurs",
svgSrc: "assets/icons/menu_tran.svg",
subTitle1: 'Ajouter Un Fournisseur',
subTitle2: 'Liste Des Fournisseurs',
subTitle3: '---------',
press1: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainScreen(Text('Hello'))),
);
},
After clicking on this in my Drawer I'm getting the error listed above.
As the error states, the correct provider isn't found above the MainScreen Widget.
See if it helps to structure your main.dart like this:
import 'package:admin/constants.dart';
import 'package:admin/controllers/MenuController.dart';
import 'package:admin/screens/dashboard/dashboard_screen.dart';
import 'package:admin/screens/main/main_screen.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => MenuController(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Admin Panel',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: bgColor,
textTheme: GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme)
.apply(bodyColor: Colors.white),
canvasColor: secondaryColor,
),
home: MainScreen(DashboardScreen()),
),
);
}
}
Related
I want to implement GetX binding methods, and as result, I got this error:
════════ Exception caught by widgets library ═══════════════════════════════════
The following message was thrown building MyApp(dirty):
"UserController" not found. You need to call "Get.put(UserController())" or "Get.lazyPut(()=>UserController())"
The relevant error-causing widget was
MyApp
lib/main.dart:9
main.dart
import 'package:donirajkrv/views/welcome.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import './router/index.dart';
import './bindings/user_binding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialBinding: UserBinding(),
home: const Scaffold(
backgroundColor: Color.fromRGBO(244, 248, 252, 1),
body: SafeArea(child: WelcomePage()),
),
getPages: [...routeList],
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: const Color(0XFFFB6394),
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
),
);
}
}
How main works:
void main() {
Get.put<UserController>(UserController());
runApp(const MyApp());
}
user_binding.dart
import 'package:get/get.dart';
import 'package:donirajkrv/controllers/user_controller.dart';
class UserBinding implements Bindings {
#override
void dependencies() {
Get.put(() => UserController());
}
}
Routelist:
import 'package:get/get.dart';
import '../views/welcome.dart';
import '../views/login.dart';
import '../views/register.dart';
import '../views/home_page.dart';
import '../middlewares/auth_middleware.dart';
import '../middlewares/back_to_home_middleware.dart';
// Routes path
import '../routes/index.dart';
List routeList = [
GetPage(
name: '/${Routes.WELCOME_PAGE}',
page: () => const WelcomePage(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.LOGIN_PAGE}',
page: () => const Login(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.REGISTER_PAGE}',
page: () => const Register(),
middlewares: [BackToHomeMiddleware()]),
GetPage(
name: '/${Routes.HOME_PAGE}',
page: () => const HomePage(),
middlewares: [AuthMiddleware()])
];
i have added the detail code for binding controller and increment function so try using this, it will definitely work
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialBinding: UserBinding(),
getPages: [...routeList],
initialRoute: RouteNames.welcomePage,
home: const Scaffold(
backgroundColor: Color.fromRGBO(244, 248, 252, 1),
),
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: const Color(0XFFFB6394),
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
),
);
}
}
class UserController extends GetxController {
var i = 0.obs;
void increment(){
i++;
}
}
class RouteNames {
static String welcomePage = "/welcomePage";
}
List routeList = [
GetPage(
name: '/${RouteNames.welcomePage}',
page: () => WelcomePage(),
),
];
//here use binding like this
class UserBinding implements Bindings {
#override
void dependencies() {
Get.put<UserController>(UserController(), permanent: true);
}
}
class WelcomePage extends StatelessWidget {
WelcomePage({Key? key}) : super(key: key);
// final userController = Get.put(UserController());
final userController = Get.find<UserController>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: Column(
children: [
Obx(() => Text(userController.i.value.toString(),
style: const TextStyle(
fontSize: 25,
color: Colors.blueAccent
),),),
ElevatedButton(onPressed: (){
userController.increment();
}, child: const Text("Button")),
],
),
);
}
}
you should make a simple change
Instead of
GetMaterialApp(
initialBinding: BindingsBuilder(() {
Get.put(UserBinding());
})...
use
initialBinding: UserBinding())...
GetMaterialApp(
initialBinding: UserBinding())...
In the user_binding.dart file you can initiate every controller that your app uses.
and then you can use it by simply declare a variable like this
UserController controller = Get.find();
//or like this:
final controller = Get.find<UserController>();
//I haven't tested the second one, but it should work.
Hope it works :)
You can also follow the example below:
https://github.com/Prosa/Flutter-GetX-Bindings-Example
I'm trying to get my head around the Providers in Flutters... but after following some tutorials, I'm still facing some issue.
When I try to run this code, it gives me an error
Error: Could not find the correct Provider above this MyHomePage Widget
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_way/MyHomePageViewModel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyHomePageViewModel(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Consumer<MyHomePageViewModel>(
builder: (context, viewModel, child) {
return Text(viewModel.text);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () =>
Provider.of<MyHomePageViewModel>(context, listen: false)
.onClicked(),
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
),
);
}
}
import 'package:flutter/foundation.dart';
class MyHomePageViewModel extends ChangeNotifier {
String text = 'Initial text';
void onClicked() {
text = 'Something was clicked';
notifyListeners();
}
}
The website where I found this example use it as
Provider.of<MainViewModel>(context, listen: false).onClicked(),
But that doesn't work either...
Before a widget that needs a provider is presented, it is required you create that particular provider before the page is built.
Checkout the working sample of your code below.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_way/MyHomePageViewModel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => MyHomePageViewModel(),
builder: (_, __) => MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Consumer<MyHomePageViewModel>(
builder: (context, viewModel, child) {
return Text(viewModel.text);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () =>
Provider.of<MyHomePageViewModel>(context, listen: false)
.onClicked(),
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
import 'package:flutter/foundation.dart';
class MyHomePageViewModel extends ChangeNotifier {
String text = 'Initial text';
void onClicked() {
text = 'Something was clicked';
notifyListeners();
}
}
In your provider code, do you have a class defined like:
class MyHomePageViewModel extends ChangeNotifier {
// your stuff here, like getter and setters, methods, etc
}
That class will deal with all the centralisation of your states, essentially acting as you'd hope - the provider.
I want to navigate through screens but I need to change only the content of the body and the appbar stays as it is. I am having 4 files namely main.dart, screen1.dart, screen2.dart, and globals.dart. Screen1 is having a button to goto Screen2 and vice versa. When I clicked the button in screen1 it need to navigate to screen 2 and vice versa, but when I clicked the button nothing is happening. Here is my code:
main.dart
import 'package:demo/globals.dart';
import 'package:demo/screen2.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
buildBody = Screen1();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrange,
title: Text('Fixed AppBar'),
centerTitle: true,
),
body: buildBody,
);
}
}
screen1.dart
import 'package:demo/screen2.dart';
import 'package:flutter/material.dart';
class Screen1 extends StatefulWidget {
#override
_Screen1State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Center(
child: FlatButton(
child: Text('Goto Screen 2', style: TextStyle(color: Colors.white)),
onPressed: () {
setState(() {
buildBody = Screen2();
});
},
),
),
);
}
}
screen2.dart
import 'package:demo/screen1.dart';
import 'package:flutter/material.dart';
class Screen2 extends StatefulWidget {
#override
_Screen2State createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.brown,
child: Center(
child: FlatButton(
child: Text(
'Goto Screen 1',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
buildBody = Screen1();
});
},
),
),
);
}
}
globals.dart
import 'package:flutter/material.dart';
Widget buildBody;
Instead of using Scaffold in main file after MaterialApp
, use it in every separated screen use you custom content and the title you want.
Check out PageView https://api.flutter.dev/flutter/widgets/PageView-class.html
From flutter docs. I think that will work or use Tabs
I found this answer about storing global configuration into globals.dart.
How can I load configuration into it from assets/config.json?
I've tried like this:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'globals.dart' as globals;
void main() async {
globals.config = jsonDecode(await rootBundle.loadString('assets/config.json'));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
...
}
The application starts with a white screen. Nothings happens, no errors. I guess that await rootBundle.loadString(...) causes the application to hang.
You can copy paste run full code below
You need to add WidgetsFlutterBinding.ensureInitialized() in main()
without this line will produce white screen
globals.dart
Map<String, dynamic> config = {};
config.json
{
"id": "1",
"name": "abc"
}
code snippet
void main() async{
WidgetsFlutterBinding.ensureInitialized();
globals.config = jsonDecode(await rootBundle.loadString('assets/config.json'));
runApp(MyApp());
}
pubspec.yaml
assets:
- assets/
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'globals.dart' as globals;
void main() async{
WidgetsFlutterBinding.ensureInitialized();
globals.config = jsonDecode(await rootBundle.loadString('assets/config.json'));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(globals.config["id"]),
Text(globals.config["name"]),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I'm starting to learn Flutter and I'm trying to use provider.
I've follow a few tutorials and now starting my side project but I'm stuck with these error:
Error: Could not find the correct Provider<CultivatorModel> above this CultivatorComponent Widget
As I wrapped the MaterialApp with the Multiproviders, it should be in the ancestor... That error does not make sense to me, I'm certainly to new to flutter and I'm missing something obvious...
Anyway, here is my code, thanks for your help.
main.dart
import 'package:provider/provider.dart';
import 'package:flutter_app/components/cultivator_component.dart';
import 'package:flutter_app/models/incarnation_model.dart';
import 'package:flutter_app/models/cultivator_model.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(builder: (context) => IncarnationModel()),
ChangeNotifierProvider(builder: (context) => CultivatorModel()),
],
child: GameApp())
);
}
class GameApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CultivatorComponent(),
);
}
}
cultivator_component.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_app/Models/cultivator_model.dart';
class CultivatorComponent extends StatelessWidget{
#override
Widget build(BuildContext context) {
final cultivatorModel = Provider.of<CultivatorModel>(context);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('${cultivatorModel.cultivator.name} is here')
],
),
);
}
}
cultivator_model
import 'package:flutter/foundation.dart';
import 'package:flutter_app/domain/cultivator.dart';
import 'package:flutter_app/domain/incarnation.dart';
class CultivatorModel with ChangeNotifier{
Cultivator _cultivator;
Cultivator get cultivator => _cultivator;
CultivatorModel(){
_cultivator = Cultivator("MyCultivator");
}
bool canCreateIncarnation() => _cultivator.canCreateIncarnation();
void addIncarnation(Incarnation incarnation){
_cultivator.incarnations.add(incarnation);
notifyListeners();
}
}
Here is how my version works, I didn't do any major changes and my configuration is IntelliJ Idea, Flutter 1.9.1+hotfix.6 • channel stable and iOS virtual device
If you would have any problem with running the next code, please contact me and I try to help.
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(builder: (context) => AnotherModel()),
ChangeNotifierProvider(builder: (context) => CultivatorModel()),
],
child: GameApp())
);
}
class GameApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CultivatorComponent(),
);
}
}
class CultivatorComponent extends StatelessWidget{
#override
Widget build(BuildContext context) {
final cultivatorModel = Provider.of<CultivatorModel>(context);
final anotherModel = Provider.of<AnotherModel>(context);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('${cultivatorModel.cultivator} is here'),
Text('${anotherModel.modelNum} is here')
],
),
);
}
}
class CultivatorModel with ChangeNotifier{
String _cultivator;
String get cultivator => _cultivator;
CultivatorModel(){
_cultivator = "MyCultivator";
}
void addIncarnation(String incarnation){
_cultivator = incarnation;
notifyListeners();
}
}
class AnotherModel with ChangeNotifier{
int _modelNum;
int get modelNum => _modelNum;
AnotherModel(){
_modelNum = 55;
}
void changeNumber(int num){
_modelNum = num;
notifyListeners();
}
}