I would like to update a page other than the one in which the user presses the button, I know that to update the page itself just use the
setState (() {})
but what I want to do is update the HomePage when the user presses a button that is on the main.dart page. How can I solve?
What I thought and that it works but badly is to use the
Navigator.push (context, MaterialPageRoute (builder: (context) => const MyApp ()));
when the user presses the button, and doing so it works because it updates my MyApp (main.dart), the problem is that when they press the button in this way you see the same animation as when you open the app and it is very ugly.
you can pass a function with setState in it to the other page and run the function after click the buttton
something like this:
class Startpage extends StatefulWidget {
const Startpage({super.key});
#override
State<Startpage> createState() => StartpageState();
}
class StartpageState extends State<Startpage> {
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(updateStartPage: () {
setState(() {
//add your logic
});
})),
),
child: const Text("navigate to second page"));
}
}
class SecondPage extends StatelessWidget {
final Function updateStartPage;
const SecondPage({super.key, required this.updateStartPage});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => updateStartPage(),
child: const Text("update parent"),
);
}
}
Related
This issue is related with github #2502.
I am using GetMaterialApp from this package.
I'm not sure if this is a bug or not.
How to make the function in the first dialog useable by using Get.toNamed()?
It happened when using the Get.toNamed().
It works fine with Navigator.push() but I need Get.toNamed for the web app.
The first page has a button that will show the first dialog.
The first dialog will show the order type button list.
When pressing an order type button, the program will find a new order of this type and open the second page with a new order data.
The second page has some work to do and this work will open the second dialog.
After finishing this work, the user will click on the back button back to the first page and find a new order again.
The problem is when the second dialog works on the second page.
The first dialog on the first page will not work.
see video example.
web example.
code example:
import 'package:flutter/material.dart';
import 'package:flutter_test_exam_bug/config/path/page_path.dart';
import 'package:get/get.dart';
Future<void> _showMyDialog({required BuildContext context, required Widget child}) async {
return showDialog<void>(
context: context,
builder: (BuildContext context) => child,
);
}
class PageTest extends StatefulWidget {
const PageTest({Key? key}) : super(key: key);
#override
_PageTestState createState() => _PageTestState();
}
class _PageTestState extends State<PageTest> {
#override
Widget build(BuildContext context) {
Widget dialog_ = Center(
child: ElevatedButton(onPressed: () => Get.toNamed(PagePath.test2), child: const Text("Open second page"))),
openDialogButton_ = ElevatedButton(
onPressed: () => _showMyDialog(context: context, child: dialog_), child: const Text("Open first dialog"));
return Scaffold(body: SafeArea(child: Center(child: openDialogButton_)));
}
}
class PageTest2 extends StatefulWidget {
const PageTest2({Key? key}) : super(key: key);
#override
State<PageTest2> createState() => _PageTest2State();
}
class _PageTest2State extends State<PageTest2> {
ButtonStyle buttonStyle = ElevatedButton.styleFrom(primary: Colors.green);
#override
Widget build(BuildContext context) {
Widget dialog_ = Center(
child: ElevatedButton(
onPressed: () => Navigator.pop(context), child: const Text("I am second dialog"), style: buttonStyle)),
openDialogButton_ = ElevatedButton(
onPressed: () => _showMyDialog(context: context, child: dialog_),
child: const Text("Open second dialog"),
style: buttonStyle);
return Scaffold(appBar: AppBar(), body: SafeArea(child: Center(child: openDialogButton_)));
}
}
I think it is a bug.
When opening a dialog, the GETX ROUTE will change to the current page again.
Follow this in https://github.com/jonataslaw/getx/issues/2502
I have two classes MainScreen and SearchScreen which uses nested function with a boolean value
For example, here in MainScreen, I have a function showMap, its return value is obtained from SearchScreen
Future showMap(bool checkValue) async {
try {
//do something
}
//somewhere in the widgets
#override
Widget build(BuildContext context) {
super.build(context);
//
GestureDetector(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchScreen(
showMapFunction: showMap)));)
}
}
NoW in my SearchScreen I have
class SearchScreen extends StatefulWidget {
final Function showMapFunction;
const SearchScreen({
this.showMapFunction
}); //,this.String});
#override
_SearchScreenState createState() => _SearchScreenState();
}
///
#override
#mustCallSuper
Widget build(BuildContext context) {
GestureDetector(
onTap: () async {
Navigator.pop(
//send back data
// context,
widget.showMapFunction(true));
},
child: Icon(Icons.arrow_back)),
}
This works fine, when I navigate back to MainScreen the function showMap is called, Is there any other way to do this perhaps with provider package or sth? This causes a lot of rebuilds to my widget tree.
What you can do is to await the result of the navigator, like the one used in the Flutter Cookbook.
void _navigateToSearch(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchScreen())),
);
}
And then, when you pop the Search Screen, do the following
GestureDetector(
onTap: () async => Navigator.pop(true),
child: Icon(Icons.arrow_back),
),
I also suggest using WillPopScope.
What I want to do is to have for the user first time reach the screen that oine alertDialog appears.
I use this code to move to another screen:
Navigator.push(context, MaterialPageRoute(builder: (context) => IfProfilePage()));
in this specific case i switch tyo IfProfilPage but what I want is to get in IfProfilePage for the first time an alertdialog which I will build later, but this dialogf will contains some information that user has to follow.
thanks
you can pass it in initstate method
it has to be a stateful widget
class DestinationPage extends StatefulWidget {
#override
_DestinationPageState createState() => _DestinationPageState();
}
class _DestinationPageState extends State<DestinationPage> {
#override
#override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
showAlertdialog(context);
});
}
and here is a example of alert dialog that you can use
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () { },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
import 'package:flutter/material.dart';
import 'fruits_listing_card.dart';
import 'fruits_page.dart';
Map<String, Widget> fruits = {
"banana": FruitsListingCards(
fruitBGColor: 0xFFF8A8B5,
fruitImagePath: 'images/fruits/banana.png',
fruitName: 'Banana',
fruitPrice: 'Rs. 105',
fruitShortDescription: 'Ripe & Tasty',
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => FruitsPage()),);
},
),
}
// Second File
import 'package:flutter/material.dart';
class FruitsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(),
),
);
}
}
Both the code are in different files.
FruitsListingCards is a widget that has a Gesture detector functionality. onTap is a parameter that takes function.
I am using FruitsListingCards in the main file and whenever a user taps on it, should go to the FruitsPage screen. But the error is not letting me to do so. Any solution with proper explanantion will help me a lot.
EDIT:
For proper understanding of code, check my repo:
https://github.com/RaghavTheGreat1/fruits_delivery/tree/master/lib
You have to provide context some how, so that it can connect the last screen and next screen.
You can wrap inside a function for that.
Following minimal code will help you more to understand.
class DeleteWidget extends StatefulWidget {
#override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class FruitsPage extends StatelessWidget {
final Function call;
FruitsPage({this.call});
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text("press"),
onPressed: call,
),
);
}
}
class NewPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Text("FruiysPage"),
),
),
);
}
}
callme(context) {
Map<String, Widget> fruits = {
"banana": FruitsPage(
call: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewPage()),
);
},
)
};
return fruits;
}
Well, I figured out the problem on omy own and it was easier than what other people had suggested me even if they haven't looked into my code committed in my GitHub repo.
The quick solution or fix was to add Navigator.push(context, MaterialPageRoute(builder: (context) => fruitsPage)); inside the anonymous function of GestureDetector in FruitsListingCards and then returning fruitsPage(which is a dynamic variable that will take Class object as parameter).
I want to navigate to the login page if there is no logged in user, otherwise display the homepage. I thought of calling Navigator.of(context).push() conditionally inside the build method but that triggers an exception. Is there some method I'm missing that I can override?
Update to add the Homepage widget
class HomePage extends StatelessWidget {
final AppUser user;
const HomePage({Key key, this.user}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Rera Farm'),
actions: <Widget>[
PopupMenuButton(
itemBuilder: (BuildContext context) {
return <PopupMenuEntry>[
PopupMenuItem(
child: ListTile(
title: Text('Settings'),
onTap: () {
Navigator.pop(context);
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context)
=> SettingsPage()
));
},
),
),
];
},
)
],
),
body: _buildBody(context));
}
And the container
class HomePageContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new StoreConnector<AppState, _ViewModel>(
converter: _ViewModel.fromStore,
builder: (BuildContext context, _ViewModel vm) {
return HomePage(
user: vm.user,
);
},
);
}
}
You need to either use a ternary in the onTap if you're using the settings button or, if you just want it to automatically send the user to the correct page when the app starts, you can put the ternary in the MyApp build method.
If you are using the settings button and just want it to pop back to the previous page if the person is not logged in then you can change NotLoggedIn() to a pop.
For some strange reason SO is refusing to post the code when it is properly formatted with four spaces, exactly as it asks, so I'm just going to make a gist.
https://gist.github.com/ScottS2017/3288c7e7e9a014430e56dd6be4c259ab
Here's how I end up doing it. I do the checks in the main method, so the user sees the splash screen set in manifest while those weird checks are made:
void main() {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences.getInstance().then((instance) {
_token = instance.getString("token");
final _loggedIn = _token != null && token != "";
runApp(MyApp(loggedIn: _loggedIn));
});
}
Then in your app add the parameters to switch:
class MyApp extends StatelessWidget {
final bool loggedIn;
MyApp({this.key, this.loggedIn});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: loggedIn ? HomePage() : LoginPage(),
);
}
}
You can also use Navigator.pushReplacement() if you need to do it below MyApp(). Just posting it here for future generations.