How can I Initialize provider? - flutter

I have implemented Provider for state management in my app. Now, I need to add some data in the class once the screen is loaded.
How I can achieve this?
stepInfo.addToList = new VaccStep(); // Need to call it one time once screen is loaded.
I have tried to call this method from initState but it's giving error!!
class AdminAddVaccination extends StatefulWidget {
#override
State createState() => new AdminAddVaccinationState();
}
class AdminAddVaccinationState extends State<AdminAddVaccination> {
#override
void initState() {
super.initState();
var stepInfo = Provider.of<StepInfo>(context); // ERROR!!
stepInfo.addToList = new VaccStep(); // ERROR!!
}
Widget build(BuildContext context) {
return new ChangeNotifierProvider(
builder: (context) => StepInfo(),
child: ScreenBody(),
);
}
}
class ScreenBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
var stepInfo = Provider.of<StepInfo>(context);
return new Scaffold(
resizeToAvoidBottomPadding: false,
key: stepInfo.scaffoldKey,
body: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new SafeArea(
top: true,
bottom: false,
child: new Stack(children: <Widget>[
new Opacity(
opacity: 0.04,
child: new Image.asset(
"assets/userProfile/heartBeat.png",
fit: BoxFit.cover,
height: 250.0,
),
),
new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
color: primaryGreen,
width: double.infinity,
height: 65.0,
child: new Stack(
children: <Widget>[
new Align(
alignment: Alignment.center,
child: stepInfo.loading
? JumpingText('......')
: new Container()),
new Align(
alignment: Alignment.centerLeft,
child: new Padding(
padding: EdgeInsets.only(top: 5.0, left: 20.0),
child: new InkWell(
child: new Container(
child: Icon(
Icons.arrow_back,
color: Colors.white,
size: 30.0,
),
),
onTap: () {
Navigator.pop(context);
},
),
),
),
],
),
),
new Padding(
padding: EdgeInsets.only(top: 0.0),
child: new Material(
elevation: 1.0,
color: Colors.transparent,
child: new Container(
color: borderColor,
width: double.infinity,
height: 5.0,
),
),
),
VaccName(),
],
),
ItemListing(),
AddStep(),
]),
)));
}
}
Error!! flutter: The following ProviderNotFoundError was thrown
building Builder: flutter: Error: Could not find the correct
Provider above this AdminAddVaccination Widget flutter:
flutter: To fix, please: flutter: flutter: * Ensure the
Provider is an ancestor to this AdminAddVaccination Widget
flutter: * Provide types to Provider flutter: * Provide
types to Consumer flutter: * Provide types to
Provider.of() flutter: * Always use package imports. Ex:
`import 'package:my_app/my_code.dart';

Simply add a constructor in your provider :
class StepInfo extends ChangeNotifier {
StepInfo() {
this.addToList = new VaccStep();
}
[...]
}

You must set listen:false and some delay to on initstate
Provider.of<StepInfo>(context, listen: false);
Future.delayed(Duration(milliseconds: 100)).then((_) {
stepInfo.addToList = new VaccStep();
});
same in this case or this

change the initState() & build() method in the AdminAddVaccination class as below:
var stepInfo;
#override
void initState() {
super.initState();
stepInfo = new StepInfo();
stepInfo.addToList = new VaccStep();
}
#override
Widget build(BuildContext context) {
return new ChangeNotifierProvider<StepInfo>(
builder: (context) => stepInfo,
child: ScreenBody(),
);
}

Related

Flutter GetX Re-Initialise GetX Controller Reset GetX Controller, Reset GetX Controller Values

I am learning Flutter GetX to my own and stuck on a point. Actually I want to know why onInit method of GetX Controlled is not calling whenever I revisit that page/dialog again.
Suppose that I have dialog with a simple TextField, a Listview the TextField is used for searching the listview. When the User enters any filter key inside the text field, the listview will be filtered.
Here is the Sample Dialog:
import 'package:flutter/material.dart';
import 'package:flutter_base_sample/util/apptheme/colors/app_colors.dart';
import 'package:flutter_base_sample/util/apptheme/styles/text_styles_util.dart';
import 'package:flutter_base_sample/util/commons/app_util.dart';
import 'package:flutter_base_sample/util/widgets/alert/controllers/country_finder_alert_controller.dart';
import 'package:flutter_base_sample/util/widgets/marquee/marquee_widget.dart';
import 'package:flutter_base_sample/util/widgets/textfields/app_text_field.dart';
import 'package:get/get.dart';
class SampleDialogWidget extends StatelessWidget {
final CountryFinderAlertController controller = Get.put(CountryFinderAlertController(),permanent: true);
#override
Widget build(BuildContext context) {
return Dialog(
insetPadding: AppUtil.dialogPadding(context),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
elevation: 0.0,
backgroundColor: Colors.white,
child: dialogContent(context),
);
}
Widget dialogContent(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Text(
"Hello Heading",
style: TextStyleUtil.quickSandBold(context, fontSize: 16, color: Colors.blue),
textAlign: TextAlign.center,
),
SizedBox(
height: 20,
),
Expanded(
child: SingleChildScrollView(
child: Container(
height: AppUtil.deviceHeight(context),
padding: EdgeInsetsDirectional.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Hello Text1"),
SizedBox(
height: 10,
),
getSearchField(context),
SizedBox(
height: 5,
),
Expanded(
child: Obx(()=> getFavoritesListView(context)),
)
],
),
),
),
),
SizedBox(
height: 20,
),
Container(
margin: EdgeInsetsDirectional.only(start: 20,end: 20),
child: ElevatedButton(
onPressed: () {},
style: ButtonStyle(
overlayColor: MaterialStateProperty.all<Color>(Colors.red),
// splashFactory: NoSplash.splashFactory,
elevation: MaterialStateProperty.all(0.5),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return AppColors.instance.black.withOpacity(0.1);
} else {
return Colors.blue; // Use the component's default.
}
},
),
),
child: Text(
"Hello Footer",
style: TextStyleUtil.quickSandBold(context, fontSize: 16, color: Colors.yellow),
textAlign: TextAlign.center,
),
),
)
],
);
}
Widget getFavoritesListView(BuildContext context) {
if (controller.favoritesList.length > 0) {
return ListView.separated(
shrinkWrap: true,
itemCount: controller.favoritesList.length,
itemBuilder: (BuildContext context, int index) => _topupFavoriteContent(context, index),
separatorBuilder: (context, index) {
return Divider(
indent: 15,
endIndent: 15,
);
},
);
} else {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"No Data Found!",
textAlign: TextAlign.center,
),
SizedBox(
height: 20,
),
],
),
);
}
}
Widget _topupFavoriteContent(BuildContext context, int index) {
final item = controller.favoritesList[index];
return InkWell(
onTap: () {
Get.back(result:item);
// AppUtil.pop(context: context, valueToReturn: item);
},
child: getChildItems(context, index));
}
Widget getChildItems(BuildContext context, int index) {
return Directionality(textDirection: TextDirection.ltr, child: getContactNumberAndNameHolder(context, index));
}
Widget getContactNumberAndNameHolder(BuildContext context, int index) {
final item = controller.favoritesList[index];
return Container(
padding: EdgeInsetsDirectional.only(start: 20, end: 20, top: 20, bottom: 10),
child: Column(
children: [
Row(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Align(
alignment: AlignmentDirectional.centerStart,
child: Text(
item.name ?? "",
style: TextStyleUtil.quickSandBold(context, fontSize: 15, color: AppColors.instance.black),
),
),
),
SizedBox(
width: 5,
),
Container(),
Align(
alignment: AlignmentDirectional.centerEnd,
child: MarqueeWidget(
child: Text(
item.dialCode ?? "",
style: TextStyleUtil.quickSandBold(context, fontSize: 15, color: Colors.blue),
),
),
),
],
)
],
),
);
}
Widget getSearchField(
BuildContext context,
) {
return Container(
margin: EdgeInsetsDirectional.only(start: 20, end: 20, top: 20),
child: Row(
children: [
Expanded(
child: AppTextField(
onChanged: (String text) {
controller.performSearchOnForFavoriteContact(text);
},
isPasswordField: false,
keyboardType: TextInputType.text,
suffixIconClickCallBack: () {},
),
)
],
));
}
}
and here is the GetX Controller:
class CountryFinderAlertController extends GetxController {
TextEditingController countrySearchFieldEditController = TextEditingController();
RxList<CountryHelperModel> favoritesList;
RxList<CountryHelperModel> originalList;
#override
void onInit() {
super.onInit();
debugPrint("Hello222");
favoritesList = <CountryHelperModel>[].obs;
originalList = <CountryHelperModel>[].obs;
}
#override
void onReady() {
super.onReady();
debugPrint("Hello111");
originalList.addAll(JSONHelperUtil.getCountries());
addAllCountries();
}
#override
void dispose() {
super.dispose();
countrySearchFieldEditController.dispose();
}
#override
void onClose() {
super.onClose();
}
void performSearchOnForFavoriteContact(String filterKey) {
if (filterKey != null && filterKey.isNotEmpty) {
List<CountryHelperModel> filteredFavoritesList = [];
debugPrint("filterKey" + filterKey);
originalList.forEach((element) {
if (element.name.toLowerCase().contains(filterKey.toLowerCase()) ||
element.countryCode.toLowerCase().contains(filterKey.toLowerCase()) ||
element.dialCode.toLowerCase().contains(filterKey.toLowerCase())) {
filteredFavoritesList.add(element);
}
});
if (filteredFavoritesList.isNotEmpty) {
favoritesList.clear();
favoritesList.addAll(filteredFavoritesList);
} else {
favoritesList.clear();
}
} else {
//reset the list
addAllCountries();
}
}
void addAllCountries() {
favoritesList.clear();
favoritesList.addAll(originalList);
}
}
So what I want is to load fresh data each time when I open this dialog. For now, if user will search for any country and close the dialog and then if reopen it the user will see the older search results.
In simple means how can GetX Controller be Reset/Destroyed or reinitialised !
Thanks in advance
So the answer to this question from me is that the Flutter pub GetX do provide a way to delete any initialised controller. Let's suppose that we only have a controller that needs to call an API in its onInit() method, every time the user will land on that specific view controller suppose!
So the solution to this problem is to just call:
Get.delete<YourControllerName>();
The thing that when it should get called is important. For me the clean way to do it, when I goto a new page I register a value to return/result callback as:
Get.to(()=>YourWidgetView());
to
Get.to(()=>YourWidgetView()).then((value) => Get.delete<YourControllerName>());
So whenever the user will leave your Widget View will delete the respected controller. In this way when the user will come again to the same widget view, the controller will re-initialised and all the controller values will be reset.
If anyone does have any better solution can share with the dev community.
Thanks
I believe it's because of ,permanent: true
Try leaving that out.
Considering this is dialog, there's no need to inject the controller using Get.put() method. Instead try this, using this approach every time we call SimpleDialogWidget, its controller will be created and disposed of when Get.back() will be called.
Step 1 : Extend your SimpleDialogWidget with GetView<CountryFinderAlertController>
class SampleDialogWidget extends GetView<CountryFinderAlertController> {...}
Step 2 : Wrap your actual widget inside Getx
class SampleDialogWidget extends GetView<CountryFinderAlertController> {
#override
Widget build(BuildContext context) {
return GetX<CountryFinderAlertController>( //Here it is
init : CountryFinderAlertController(), // like this
builder: (controller) => Dialog(
insetPadding: AppUtil.dialogPadding(context),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
elevation: 0.0,
backgroundColor: Colors.white,
child: dialogContent(controller, context), // Also, pass the controller to dialogContent function
);
);
}
}
That will solve your problem.
Disposing your resources always come after disposing super resources. So change the following
#override
void dispose() {
super.dispose();
countrySearchFieldEditController.dispose();
}
with
#override
void dispose() {
countrySearchFieldEditController.dispose();
super.dispose();
}
If it still not works, please attach the binding file code as well.
Controller won't get disposed:
class SampleDialogWidget extends StatelessWidget {
final CountryFinderAlertController controller = Get.put(CountryFinderAlertController(),permanent: true);
#override
Widget build(BuildContext context) {
return Dialog(
Instantiation & registration (Get.put(...)) should not be done as a field.
Otherwise, the registration of controller is attached to LandingScreen, not MainScreen. And Controller will only get disposed when LandingScreen is disposed. Since that's the home Widget in the code above, disposal only happens upon app exit.
Fix: Move Get.put to the build() method.
class SampleDialogWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
final CountryFinderAlertController controller = Get.put(CountryFinderAlertController());
return Dialog(
Others said to initialize the controller, but sometimes there are other ways. I recommend using GetWidget instead StatelessWidget
class SampleDialogWidget extends GetWidget<CountryFinderAlertController> {...}
and 'your_any_screen_bindings.dart' file seems like
class YourAnyScreenBindings implements Bindings {
#override
void dependencies() {
Get.put(YourAnyScreenCtrl());
Get.create(() => CountryFinderAlertController());
}
}
and 'your_routes.dart' file will be...
List<GetPage<dynamic>> getPages = [
GetPage(
name: '/your_any_screen',
page: () => YourAnyScreen(),
binding: YourAnyScreenBindings(),
),
]
Now your dialog widget will be paired with a FRESH controller every time.

FlatButton taking up whole screen in flutter web

I am building a webapp with flutter where I want to add google sign in. The button itself works fine, but whatever I try, it just takes up my whole screen. I tried putting the button in the class in a container and putting it in a sizedbox on the page I actually want to use it on, and limiting the size of the button itself. This is my first time with flutter web, so I'd really like to know why this is happening.
Here is my code for the button:
class GoogleButton extends StatefulWidget {
#override
_GoogleButtonState createState() => _GoogleButtonState();
final DatabaseRepo databaseRepo;
final InitRepo initRepo;
GoogleButton(this.databaseRepo, this.initRepo);
}
class _GoogleButtonState extends State<GoogleButton> {
bool _isProcessing = false;
#override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height / 10,
child: FlatButton(
height: MediaQuery.of(context).size.height / 10,
onPressed: () async {
setState(() {
_isProcessing = true;
});
await signInWithGoogle().then((result) {
print(result);
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) =>
MainPage(widget.databaseRepo, widget.initRepo),
),
);
}).catchError((error) {
print('Registration Error: $error');
});
setState(() {
_isProcessing = false;
});
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: _isProcessing
? CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
Colors.blueGrey,
),
)
: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
'Bejelentkezés',
style: TextStyle(
fontSize: 20,
color: Colors.blueGrey,
),
))
]))),
);
}
}
Just to be on the safe side, here is the code for the page itself:
import 'package:flutter/material.dart';
import 'package:foci_dev/repo/database_repo.dart';
import 'package:foci_dev/repo/init_repo.dart';
import 'package:foci_dev/ui/google_button.dart';
class SignInPage extends StatelessWidget {
final DatabaseRepo databaseRepo;
final InitRepo initRepo;
SignInPage(this.databaseRepo, this.initRepo);
#override
Widget build(BuildContext context) {
return Container(
color: Colors.grey[800],
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 5,
width: MediaQuery.of(context).size.height / 5,
child: Column(
children: [
Image(image: AssetImage('lib/assets/icon.png')),
Container(
height: MediaQuery.of(context).size.height / 10,
child: ButtonTheme(
height: 20,
child:
GoogleButton(this.databaseRepo, this.initRepo))),
],
)),
],
),
);
}
}
Thank you very much for your help, I really don't know what to do.

RefreshIndicator not working with SingleChildScrollView as child

I am trying to use RefreshIndicator to reload a list I show on my home screen. The code looks similar to this:
class Home extends StatefulWidget {
#override
_StartHomeState createState() => _StartHomeState();
}
class _StartHomeState extends State<Home> {
EventsList events;
#override
void initState() {
super.initState();
events = EventsList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: RefreshIndicator(
onRefresh: resfreshEventList,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
children: [
HomeTopBar(),
events,
],
),
),
),
);
}
Future<Null> resfreshEventList() async {
await Future.delayed(Duration(seconds: 2));
setState(() {
events = EventsList();
});
return null;
}
}
EventsList is another stateful widget that will call an API and map the response to a list of widgets. I have tried setting the physics property of the SingleChildScrollView as mentioned here: https://github.com/flutter/flutter/issues/22180 but no luck. Using ListView instead of the SingleChildScrollView doesn't work either.
It seems to be working fine in this example When I pull to refresh then resfreshEventList gets fired and also setState is working without any problem.
Here is the code which I am using:
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
#override
_StartHomeState createState() => _StartHomeState();
}
class _StartHomeState extends State<Home> {
// EventsList events;
int number = 0;
#override
// void initState() {
// super.initState();
// events = EventsList();
// }
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("RefreshIndicator Example"),
),
resizeToAvoidBottomPadding: false,
body: RefreshIndicator(
onRefresh: resfreshEventList,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
children: [
// HomeTopBar(),
// events,
Container(
height: 200,
width: 200,
color: Colors.red,
child: Center(
child: Text(number.toString()),
),
),
Divider(),
Container(
height: 200,
width: 200,
color: Colors.red,
child: Center(
child: Text(number.toString()),
),
),
Divider(),
Container(
height: 200,
width: 200,
color: Colors.red,
child: Center(
child: Text(number.toString()),
),
),
Divider(),
Container(
height: 200,
width: 200,
color: Colors.red,
child: Center(
child: Text(number.toString()),
),
),
Divider(),
Container(
height: 200,
width: 200,
color: Colors.red,
child: Center(
child: Text(number.toString()),
),
)
],
),
),
),
));
}
Future<Null> resfreshEventList() async {
// await Future.delayed(Duration(seconds: 2));
// setState(() {
// events = EventsList();
// });
setState(() {
number = number + 1;
});
print("Refresh Pressed");
return null;
}
}
Output:

How to navigate to another page within a stack in flutter?

I am currently trying to manage the navigation logic within the flutter stack I have created.
I would like to add separate page navigation to each of the list items listed:
List<String> images = [
"assets/berries-chocolates-delicious-918327.jpg",
"assets/adult-beauty-cosmetic-1029896.jpg",
"assets/aerial-shot-architecture-beach-1488515.jpg",
"assets/brush-brushes-cosmetics-212236.jpg",
];
List<String> title = [
"Cadbury",
"Biotherme",
"Trip Advisor",
"L'Oreal Paris",
];
> This is the associated stack logic code in another file:
Stack(
children: <Widget>[
CardScrollWidget(currentPage),
Positioned.fill(
child: PageView.builder(
itemCount: images.length,
controller: controller,
reverse: true,
itemBuilder: (context, index) {
return Container();
},
),
)
],
),
// SizedBox(
// height: 10.0,
// ),
This is the associated widget file code:
import 'package:flutter/material.dart';
import '../screens/introductory_screen.dart';
import 'data.dart';
import 'dart:math';
import '../constants/constants.dart';
class CardScrollWidget extends StatefulWidget {
var currentPage;
CardScrollWidget(this.currentPage);
#override
_CardScrollWidgetState createState() => _CardScrollWidgetState();
}
class _CardScrollWidgetState extends State<CardScrollWidget> {
var padding = 20.0;
var verticalInset = 20.0;
#override
Widget build(BuildContext context) {
return new AspectRatio(
aspectRatio: widgetAspectRatio,
child: LayoutBuilder(builder: (context, contraints) {
var width = contraints.maxWidth;
var height = contraints.maxHeight;
var safeWidth = width - 2 * padding;
var safeHeight = height - 2 * padding;
var heightOfPrimaryCard = safeHeight;
var widthOfPrimaryCard = heightOfPrimaryCard * cardAspectRatio;
var primaryCardLeft = safeWidth - widthOfPrimaryCard;
var horizontalInset = primaryCardLeft / 2;
List<Widget> cardList = List();
for (var i = 0; i < images.length; i++) {
var delta = i - widget.currentPage;
bool isOnRight = delta > 0;
var start = padding +
max(
primaryCardLeft -
horizontalInset * -delta * (isOnRight ? 15 : 1),
0.0);
var cardItem = Positioned.directional(
top: padding + verticalInset * max(-delta, 0.0),
bottom: padding + verticalInset * max(-delta, 0.0),
start: start,
textDirection: TextDirection.rtl,
child: ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset(3.0, 6.0),
blurRadius: 10.0)
]),
child: AspectRatio(
aspectRatio: cardAspectRatio,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.asset(
images[i],
fit: BoxFit.cover,
),
Align(
alignment: Alignment.bottomLeft,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: const EdgeInsets.all(6.0),
This is where a gesture detector will be added to create a navigation link
child: Text(
title[i],
style: kCampaignLabelStyle,
),
),
),
),
This is where a gesture detector will be added to create a navigation link
// SizedBox(
// height: 10.0,
// ),
// Padding(
// padding: const EdgeInsets.only(
// left: 12.0, bottom: 12.0),
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: 22.0, vertical: 6.0),
// decoration: BoxDecoration(
// color: Colors.deepPurpleAccent,
// borderRadius: BorderRadius.circular(20.0)),
// child: Text(
// "Read More",
// style: TextStyle(color: Colors.white),
// ),
// ),
// )
],
),
)
],
),
),
),
),
);
cardList.add(cardItem);
}
return Stack(
children: cardList,
);
}),
);
}
}
If anyone can help with the navigation logic, I would appreciate it.
create seperate files
Cadbury.dart
class Cadbury extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return CadburyState();
}
}
class CadburyState extends State<DashboardApp> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Cadbury Screen"),
backgroundColor: MyColor.colorRed,
),
backgroundColor: MyColor.colorRed,
body: new Center());
}
}
Biotherme.dart
class Biotherme extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return BiothermeState();
}
}
class BiothermeState extends State<Biotherme> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Biotherme Screen"),
backgroundColor: MyColor.colorRed,
),
backgroundColor: MyColor.colorRed,
body: new Center());
}
}
and make the redirections like this
// common function to create button and redirects the page which is in callback name
Widget buttonBuilder(
String buttonText, BuildContext context, Widget callbackName) {
return new RaisedButton(
child: Text(buttonText),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => callbackName));
});
}
// home redirection screen which redirects to the cadbury and Biotherme screen
class RedirectionScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text("Home Screen")),
body: Center(
child: new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buttonBuilder('Cadbury Screen', context, Cadbury()),
buttonBuilder('Biotherme Screen', context, Biotherme()),
],
),
));
}
}
try this below code for Navigation, it works for me
If you want to navigate the page on the button's click event then write code
return new RaisedButton(
child: Text(buttonText),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => redirection_page_name));
});
Note: Here redirection_page_name is the page or widget name which you want to be load on the button's click event.
The original syntax is
Navigator.push(context, MaterialPageRoute(builder: (context) => redirection_page_name));
here context is the current screen widget context which is built, and redirection_page_name is the new page/widget which is being loaded.

Flutter: Calling SetState() from another class

I am trying to make a simple image that appears or disappears when a button is pushed. This button resides in a separate class to the image, so in Flutter this creates a massive headache of an issue.
I have read many forums on this and I have tried all the solutions posed but none of them are working for me.
What I am trying to do:
class SinglePlayerMode extends StatefulWidget {
#override
SinglePlayerModeParentState createState() => SinglePlayerModeParentState();
}
class SinglePlayerModeParentState extends State<SinglePlayerMode> {\
bool coinVisible = false;
toggleCoin() {
setState(() {
coinVisible = !coinVisible;
});
}
Widget topMenuRow() {
return Stack(
children: [
Column(
children: [
coinVisible == true ?
Padding(
padding: EdgeInsets.all(50),
child: Container(
height: 60,
width: 60,
color: Colors.blueGrey[0],
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: ExactAssetImage('lib/images/coin_head.jpg'),
fit: BoxFit.cover,
),
),
),
) : Container(
height: 60,
width: 60,
color: Colors.black,
),
],
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
children: [
topMenuRow(),
SizedBox(height: 40),
],
),
),
);
}
And this is the separate class which I would like to trigger the SetState() on coinVisible from:
class dropDownMenu extends StatefulWidget { #override
_dropDownMenuState createState() => _dropDownMenuState();
}
class _dropDownMenuState extends State<dropDownMenu> {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget> [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
child: Opacity(
opacity: 0.0,
child: FloatingActionButton(
heroTag: null,
onPressed: (){
//SOMEHOW CALL SetState() ON coinVisble HERE!
},
),
),
);
}
}
But nothing I have tried is working, and I have lost hours.
It simple, you need to send your SinglePlayMode::toggleCoin function as callback to dropDownMenu class.
class dropDownMenu extends StatefulWidget {
final _callback; // callback reference holder
//you will pass the callback here in constructor
dropDownMenu( {#required void toggleCoinCallback() } ) :
_callback = toggleCoinCallback;
#override
_dropDownMenuState createState() => _dropDownMenuState();
}
class _dropDownMenuState extends State<dropDownMenu> {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget> [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
child: Opacity(
opacity: 0.0,
child: FloatingActionButton(
heroTag: null,
onPressed: (){
widget?._callback(); // callback calling
},
),
),
);
}
}
Then when you create a dropDownMenu class instance in your SinglePlayerMode class you will do
dropDownMenu(
toggleCoinCallback: toogleCoin,
);