I have some IconButton in persistentFooterButtons that navigate to other screens but if I pressed double on any button and press the back button it redirects two times. if I pressed the button multiple times and press the back button it shows me the same page. so I want to click only one time and when it clicks and shows me the page the button will disable and won't press I think it works but I know how do I do that. please help me with that issue.
Here is my code:-
class Footer extends StatefulWidget {
Footer({Key? key}) : super(key: key);
#override
_Footer createState() => _Footer();
}
class _Footer extends State<Footer>{
bool _isButtonTapped1 = false;
bool _isButtonTapped2 = false;
bool _isButtonTapped3 = false;
bool _isButtonTapped4 = false;
#override
Widget build(BuildContext context){
return MaterialApp(
home: Scaffold(
appBar: AppBar()
persistentFooterButtons: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => const CardApp()),
(Route<dynamic> route) => false);
},
icon: SvgPicture.asset(
'assets/images/f_home.svg',
),
),
Spacer(),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Matches()),
);
},
icon: SvgPicture.asset(
'assets/images/f_fav.svg',
),
),
Spacer(),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Message()),
);
},
icon: SvgPicture.asset(
'assets/images/f_chat.svg',
),
),
Spacer(),
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Favorites()),
);
},
icon: SvgPicture.asset(
'assets/images/f_star.svg',
),
),
]
)
],
),
);
}
}
Here is my code of persistentFooterButtons which added four buttons and each button navigates its own screen.
please help me ho disable multiple onPressed on every button. if anyone knows please help me out
if you want to prevent multiple press from user, in InkWell widget, use this:
onDoubleTap: (){},
Related
I am working on an flutter application where it has more than 5 screens, I want to handle the back button of android, for example, when I logged in on app, it display the dashboard screen, so when I move to profile and then move to history screen, and when I click on back button on history screen it should navigate to profile screen, because the last screen I visited before history screen is profile, but it display the first screen which login screen.
I found the solution which works like when I click on back button it close the app.
Update:
My screens are navigating from drawer and from bottom navigation, there is only login screen where i use login button and calling dashboard screen onpressed function, other than this there is no button on any screen which navigate to other screens. here is the code for drawer and bottom navigation.
this is line of code i am using on login button
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
drawer and bottom navigation code:
Code:
class Employee extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primaryColor: Colors.blue
),
home: EmployeeNavigation(),
);
}
}
int _selectedTab = 0;
final _pageOptions = [
EmployeeDashboard(),
location(),
Profile()
];
String getname="";
String getemail="";
String getdesignation="";
String getaccesstoken="";
String getdate;
String getTime;
// ignore: must_be_immutable
class EmployeeNavigation extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return EmployeeNavigationState();
}
}
class EmployeeNavigationState extends State<EmployeeNavigation> {
var email;
var designation;
var date;
bool valuefirst = false;
String backtext="";
#override
Widget build(BuildContext context) {
//i used this too but it doesn't work.
return WillPopScope(
onWillPop: () async {
if (_selectedTab == 0) {
return true;
}
setState(() {
_selectedTab = 0;
});
return false;
},
child:Scaffold(
drawer:Emp_DrawerCode(),
body: _pageOptions[_selectedTab],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.blue[50],
type: BottomNavigationBarType.fixed,
currentIndex: _selectedTab,
onTap: (value) {
print(value);
setState(() {
_selectedTab = value;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "Home"),
BottomNavigationBarItem(icon: Icon(Icons.location_on), label: "Location"),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: "Profile",
),
],
)));
}
}
class Emp_DrawerCode extends StatefulWidget {
#override
_Emp_DrawerCodeState createState() => _Emp_DrawerCodeState();
}
class _Emp_DrawerCodeState extends State<Emp_DrawerCode> {
SharedPreferences myPrefs;
name() async{
myPrefs=await SharedPreferences.getInstance();
setState(() {
getname=myPrefs.getString('name');
getemail=myPrefs.getString('email');
getdesignation=myPrefs.getString('designation');
});
}
void initState(){
name();
}
#override
Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
padding: const EdgeInsets.all(0.0),
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text(getname),
accountEmail: new Text(getemail),
currentAccountPicture: new CircleAvatar(
backgroundColor:
Theme.of(context).platform == TargetPlatform.android
? Colors.white
: Colors.blue,
child: Text(
getname[0][0],
style: TextStyle(fontSize: 40.0),
),
),
),
new ListTile(
title: new Text('Home'),
leading: Icon(Icons.dashboard,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=> EmployeeNavigation()
)
);
},
),
new ListTile(
title: new Text('Request for leave'),
leading: Icon(Icons.request_page,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>RequestForLeave()
)
);
},
),
new ExpansionTile(
title: new Text('History'),
children: <Widget>[
ListTile(
title:new Text("My Attendance"),
leading: Icon(Icons.assessment_outlined ,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>new MyAttendance()
)
);
},
),
ListTile(
title:new Text("Leaves"),
leading: Icon(Icons.assessment_outlined,color:Colors.grey ),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>new LeaveHistory()
)
);
},
),
],
leading: Icon(Icons.history,),
),
new ListTile(
title: new Text('Log out'),
leading: Icon(Icons.logout,color:Colors.grey),
onTap: (){
myPrefs.setBool('login', true);
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>
Login()
)
);
},
),
],
),
);
}
}
kindly please help how to do this.
I am using navigator.push method and it is acting as you want.
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.blue),
onPressed: () => Navigator.of(context).pop(),
),
title: Text("Sample"),
centerTitle: true,
),
I wish it solve your problem.
You need to first clarify your question a bit more.
Are using page view/ are you talking about a scenario where all are separately navigable screens or some different scenario ?
I am considering it as the second scenario when all are separately navigable screens.
In that case, every time user navigates to next screen you must use Navigator.pushNamed() / Navigator.push() as for now I think you are using Navigator.pushReplacement() which is causing this issue probably.
Navigator is nothing but a class aware of the stack of screens in the memory and so are the functions it provides us with. A simple push would mean pushing over the last pushed screen whereas pushing a replacement would replace the last pushed screen ultimately preventing you from navigating to the last pushed screen. Exactly like how it would work for a stack data structure.
Firstly Wrap your Scaffold with WillPopScope
return WillPopScope(
onWillPop: _onBackPressed,
child : Scaffold());
And then you can call the Function that handles the back press.
// Back Button Android Behaviour
Future<bool> _onBackPressed() async {
final shouldPop = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Are you sure you want to leave this page?",
style: TextStyle(
color: Colors.black,
fontSize: 25.0,
fontWeight: FontWeight.w500,
),
),
actions: <Widget>[
SizedBox(width: 16),
InkWell(
onTap: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => HomeScreen(), // Destination
),
(route) => false,
);
},
child: Container(
padding: EdgeInsets.all(8.0),
child: Text(
"LEAVE",
style: TextStyle(
color: Colors.red,
fontSize: 20.0,
fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(width: 8.0),
InkWell(
onTap: () => Navigator.of(context).pop(false),
child: Container(
padding: EdgeInsets.all(8.0),
child: Text(
"DO NOT LEAVE",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
fontWeight: FontWeight.w500,
),
),
),
),
],
));
return shouldPop ?? false;
}
I have a simple code
class A_View extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ViewModelBuilder<A_ViewModel>.reactive(
viewModelBuilder: () => A_ViewModel(),
builder: (context, model, child) => Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context, model.value)),
),
body: model.isBusy
? CircularProgressIndicator()
: ListView.builder(
.............
),
),
);
}
}
class A_ViewModel extends FutureViewModel {
int value = 10;
}
when i click button back in appbar . i was get value form pop
but when i click back button on my phone -> value is null
how to back button on my phone return value same button in appbar ?, please help me
To get the value from the back button pressed on your phone, you can use the willPopScope widget. Have a look into the below code:
return ViewModelBuilder<A_ViewModel>.reactive(
viewModelBuilder: () => A_ViewModel(),
builder: (context, model, child) => WillPopScope(
//here you can do the magic
onWillPop: ()async{
Navigator.pop(context, model.value);
return Future<bool>.value(false);
},
child:Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context, model.value)),
),
body: model.isBusy
? CircularProgressIndicator()
: ListView.builder(
.............
),
)
)
);
I am trying to get text to show on the front landing page that has the FloatingActionButton, rather than redirect the text input onto a new page. Can someone point out where I am going wrong? Any help is appreciated
Below is the code, I have removed the code the Class code that the FloatingActionButton is on the Class is Home Extends StatelessWidget:
floatingActionButton: FloatingActionButton(
onPressed: () {
createAlertDialog(context);
},
child: Icon(Icons.add),
backgroundColor: Colors.red,
),
);
}
createAlertDialog(BuildContext context) {
showDialog(context: context, builder: (context) {
String value;
return AlertDialog(
title: Text("Add RSS URL"),
content: TextField(
keyboardType: TextInputType.emailAddress,
onChanged: (text) {
value = text;
},
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text('Add'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Dude(value)));
},
),
],
);
},
);
}
}
class URL extends StatefulWidget {
final String text;
URL(this.text);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<URL> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Text(widget.text),
),
),
);
}
}
I'm unsure what you're asking but your button opens a Modal Dialog which is a pop-up screen.
If you want to remain on the same screen, then get rid of the modal.
You want to use a combination of Visibility() which takes in a visibility: boolean parameter.
Let's say you declare bool _visibility = false;
When the user presses the FloatingActionButton, you want
onPressed: () => {setState(() { _visibility = !_visibility }); }
https://api.flutter.dev/flutter/widgets/Visibility-class.html
Hi I am pretty new to flutter and software development in general. I can't seem to understand how do I navigate from one activity to another.
What I really want is when I press the login button it should navigate me to a new activity
void main() {
runApp(MaterialApp(
title: 'button navigation',
home: HomeActivity(),
));
}
class HomeActivity extends StatelessWidget{
gotoSecondActivity(BuildContext context){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondActivity()),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Go To Second Screen'),
color: Colors.red,
textColor: Colors.white,
onPressed: () {
gotoSecondActivity(context);
},
),
),
);
}
}
class SecondActivity extends StatelessWidget {
goBack(BuildContext context){
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
goBack(context);
},
color: Colors.green,
textColor: Colors.white,
child: Text('Go Back To Previous Screen'),
),
),
);
}
}
Here is the code for second activity which i want to navigate to:
class SecondActivity extends StatelessWidget {
goBack(BuildContext context){
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
goBack(context);
},
color: Colors.green,
textColor: Colors.white,
child: Text('Go Back To Previous Screen'),
),
),
);
}
}
How does onclick function works on flutter and how do I implement this on my button
For you to understand the concept of navigation, think of a stack of papers stacked.
Every time you use:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => AnotherPage(),));
you are "putting" a paper on that pile.
push is used to "put" a new paper in that pile.
pop is used to "pull" a paper out of that pile,in other words, you will go back to the previous paper(page)
Ex: Navigator.pop(context);
And there are other types of navigation, I suggest you see the documentation after, as #dm_tr said above.
To navigate from one screen to another, you must use the Navigator. Here is an example to navigate on another page which class name is AnotherPage as you may see.
Navigator.of(context).push(MaterialPageRoute(builder: (context) => AnotherPage(),));
But, while this may answer your question, consider learning flutter basics first before trying to make an App. Here is an example of a good explanation of Navigation
You have to use navigator.
Create a class and put that inside:
Future push(BuildContext context, Widget page, {bool replace = false}) {
if(replace) {
return Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) {
return page;
}));
}
return Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
return page;
}));
}
bool pop<T extends Object>(BuildContext context, [ T result ]) {
if(Navigator.canPop(context)) {
Navigator.pop(context);
return true;
}
return false;
}
After that you can navigate between the pages with this:
push(context, yourActivity());
pop(context);
I have Flutter App with nested Navigator and I want to override "onBackPressed" using WillPopScope in my nested screen.
Let's say I have MainScreen, PrimaryScreen, and SecondaryScreen.
PrimaryScreen is nested Navigator, it have several screen like PrimaryOneScreen, PrimaryTwoScreen, and PrimaryThreeScreen.
SecondaryScreen is also a nested Navigator, just like PrimaryScreen, it have 3 screens.
Here the illustration of what i want to achieve
MainScreen -> PrimaryScreen(PrimaryOneScreen -> PrimaryTwoScreen -> PrimaryThreeScreen)
When my position on PrimaryTwoScreen, I want to get back to PrimaryOneScreen with overriding "onBackPressed" using WillPopScope Widget. But onWillPop never called when I press back button, and my screen go back directly to MainScreen.
Here are my codes
MainScreen.dart
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MainApp(),
onGenerateRoute: (settings){
WidgetBuilder builder;
switch(settings.name){
case 'primary' :
builder = (BuildContext _) => PrimaryScreen();
break;
case 'secondary' :
builder = (BuildContext _) => SecondaryScreen();
break;
case 'main' :
builder = (BuildContext _) => MainApp();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
);
}
}
class MainApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary');
},
child: Text('To Page Primary'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'secondary');
},
child: Text('To Page Secondary'),
)
],
),
);
}
}
PrimaryScreen.dart
class PrimaryScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Navigator(
initialRoute: 'primary/pageone',
onGenerateRoute: (RouteSettings settings){
WidgetBuilder builder;
switch(settings.name){
case 'primary/pageone' :
builder = (BuildContext _) => PrimaryOneScreen();
break;
case 'primary/pagetwo' :
builder = (BuildContext _) => PrimaryTwoScreen();
break;
case 'primary/pagethree' :
builder = (BuildContext _) => PrimaryThreeScreen();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
);
}
}
PrimaryOneScreen.dart
class PrimaryOneScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Primary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagetwo');
},
child: Text('To Page Two'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagethree');
},
child: Text('To Page Three'),
),
],
),
),
);
}
}
PrimaryTwoScreen.dart
class PrimaryTwoScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: ()async{
print('willPopScope');
Navigator.of(context, rootNavigator: false).pop();
return true;
},
child: Scaffold(
appBar: AppBar(
title: Text('Secondary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pageone');
},
child: Text('To Page One'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagethree');
},
child: Text('To Page Three'),
),
],
),
),
),
);
}
}
PrimaryThreeScreen.dart
class PrimaryThreeScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Primary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pageone');
},
child: Text('To Page One'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagetwo');
},
child: Text('To Page Two'),
)
],
),
),
);
}
}
EDIT
I added an image to illustrate what I want to achieve.
How to pop only on nested navigator?
Thanks!
When pressing the back button, I think it will use the main navigator of your app, because it doesn't know the nested navigator what you want to interact with.
To solve it, you have to assign a key for your navigator to be able to use it later. And adding a WillPopScope at widget which you use your nested navigator to handle user action.
Based on your example, I added some code. Noting, the maybePop() function will call the WillPopScope of your widget of the nested navigator. If you call pop(), it will pop directly, ignoring the WillPopScope of your widget.
class PrimaryScreen extends StatelessWidget{
final _navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_navigatorKey.currentState != null) {
_navigatorKey.currentState!.maybePop();
return false;
}
return true;
},
child: Navigator(
key: _navigatorKey,
initialRoute: 'primary/pageone',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch(settings.name){
case 'primary/pageone' :
builder = (BuildContext _) => PrimaryOneScreen();
break;
case 'primary/pagetwo' :
builder = (BuildContext _) => PrimaryTwoScreen();
break;
case 'primary/pagethree' :
builder = (BuildContext _) => PrimaryThreeScreen();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
),
);
}
}
Try with this link https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31
Check Use-case : pushReplacementNamed tag description