Related
I am relatively new to flutter_bloc, so forgive me if this is a simple question. I have a ListView.builder that renders out a list from my API, and my goal is to paginate this list. I have accomplished that, but the problem is that when I add new items to the list from my bloc, the entire ListView is rebuilt and the page jumps back up to the first item in the list.
Here is my bloc: I think the problem is that I am emitting the "MemesBlocLoaded" state at the end again? Or is it something else?
final ApiRepository apiRepository;
int page = 0;
MemesBlocBloc(this.apiRepository) : super(MemesBlocInitial()) {
on<GetMemesList>((event, emit) async {
try {
emit(MemesBlocLoading());
List memesList = await apiRepository.fetchMemes(page);
emit(MemesBlocLoaded(memesList));
page++;
on<GetMore>((event, emit) async {
emit(const MemesBlocLoadingMore(true));
List memesListMore = await apiRepository.fetchMemes(page);
memesList.addAll(memesListMore);
emit(const MemesBlocLoadingMore(false));
emit(MemesBlocLoaded(memesList));
page++;
});
} on NetworkError {
emit(const MemesBlocError("Failed to fetch data."));
}
});
}
}
Edited with the build method:
if (state is MemesBlocLoaded) {
return SingleChildScrollView(
child: Column(
children: [
ListView.builder(
primary: false,
shrinkWrap: true,
itemCount: state.memes.length,
itemBuilder: (context, index) {
return Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
state.memes[index].url,
width: double.infinity,
height: 400,
fit: BoxFit.cover,
),
),
),
Positioned(
right: 16,
bottom: 16,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.arrow_upward),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.arrow_downward),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.comment),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.save_alt_outlined,
color: Colors.white,
)),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.share,
color: Colors.white,
)),
IconButton(
onPressed: () {},
icon: const Icon(Icons.report_outlined),
color: Colors.white,
),
Padding(
padding:
const EdgeInsets.only(right: 4.0),
child: GestureDetector(
onTap: () {
print('profile');
},
child: const CircleAvatar(
radius: 16,
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80'),
)),
)
],
),
)
],
);
}),
state.memes.length >= 1
? state is MemesBlocLoadingMore
? const Center(
child: CircularProgressIndicator(
color: Colors.black),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white),
onPressed: () async {
context
.read<MemesBlocBloc>()
.add(GetMore());
},
child: const Text('View more',
style:
TextStyle(color: Colors.black))),
)
: const SizedBox()
],
),
);
}
I am a beginner with flutter, I had just started a few days ago. I want to go from one page to another page . But when I use the navigator it shows an error.
I've tried to solve it using some answers to similar problems on stack overflow, but I can't solve it. Also, I am not able to understand those properly.
These are some of them:
Undefined name 'context'
_buildDrawer() {
return ClipPath(
clipper: OvalRightBorderClipper(),
child: Drawer(
child: Container(
padding: const EdgeInsets.only(left: 16.0, right: 40),
decoration: BoxDecoration(
color: primary, boxShadow: [BoxShadow(color: Colors.black45)]),
width: 300,
child: SafeArea(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: IconButton(
icon: Icon(
Icons.power_settings_new,
color: active,
),
onPressed: () {},
),
),
Container(
height: 90,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient:
LinearGradient(colors: [Colors.pink, Colors.red])),
child: CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(profile),
),
),
SizedBox(height: 5.0),
Text(
"Mohd Amin bin Yaakob",
style: TextStyle(color: Colors.white, fontSize: 18.0),
),
Text(
"Pegawai",
style: TextStyle(color: active, fontSize: 16.0),
),
SizedBox(height: 30.0),
_buildRow(Icons.home, "Home", () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return HomePageWidgetPage();
},
),
);
}),
_buildDivider(),
_buildRow(Icons.home, "Home", () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return HomePageWidgetPage();
},
),
);
}),
_buildDivider(),
_buildRow(Icons.home, "Home", () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return HomePageWidgetPage();
},
),
);
}),
_buildDivider(),
_buildRow(Icons.home, "Home", () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return HomePageWidgetPage();
},
),
);
}),
_buildDivider(),
_buildRow(Icons.home, "Home", () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) {
return HomePageWidgetPage();
},
),
);
}),
_buildDivider(),
],
),
),
),
),
),
);
}
Divider _buildDivider() {
return Divider(
color: active,
);
}
Widget _buildRow(IconData icon, String title, VoidCallback onTap) {
final TextStyle tStyle = TextStyle(color: active, fontSize: 16.0);
return InkWell(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(
icon,
color: active,
),
SizedBox(width: 10.0),
Text(
title,
style: tStyle,
),
],
),
),
onTap: onTap,
);
}
}
Undefined name 'context' in flutter navigation
You can pass the context like
_buildDrawer(BuildContext context){
And the place you call this method
_buildDrawer(context)
i'm a bit new to flutter and i'm trying to teach myself to build a groceries list, which will be linked to an API backend. I want the text on a listtile to be editable ontap, so if the user makes a typo they can quickly edit the listtile without going through an additional dialogue.
Screenshot of list tiles
Code:
Widget _shoppingListItem() {
return ListView.builder(
itemCount:
_shoppingList.shoppingListCategories.first.shoppingListItems.length,
itemBuilder: (context, index) {
return Dismissible(
background: Container(
child: Text("Delete",
style: TextStyle(
fontWeight: FontWeight.normal, color: Colors.white)),
color: Colors.red,
),
confirmDismiss: (direction) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Sure??'),
content: Text('Delete'),
actions: <Widget>[
FlatButton(
onPressed: () {
// Navigator.pop(context, false);
Navigator.of(
context,
// rootNavigator: true,
).pop(false);
},
child: Text('No'),
),
FlatButton(
onPressed: () {
// Navigator.pop(context, true);
Navigator.of(
context,
// rootNavigator: true,
).pop(true);
},
child: Text('Yes'),
),
],
);
},
);
},
key: UniqueKey(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1,
blurRadius: 6,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: ListTile(
title: Text(
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemName,
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
color: ColorPalette.dark2,
icon: icons.shoppingMinus.image(size: 24),
onPressed: () {
setState(() {
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemCount--;
});
},
),
Text(
"${_shoppingList.shoppingListCategories.first.shoppingListItems[index].itemCount}",
style: TextStyle(
color: ColorPalette.dark2,
),
),
IconButton(
color: ColorPalette.dark2,
icon: icons.shoppingPlus.image(size: 24),
onPressed: () {
setState(() {
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemCount++;
});
},
),
],
),
),
),
),
);
},
);
}
}
This is the output:
I try to make an app but when I use the TextButton, I get the space between two Buttons
I need one by one without space
If I use the Expanded Widget, ScrollChildView doesn't work
I try but I can't clear this stuff.
I try to make this type of TextButton.
Anyone know or have any idea about this?
import "package:flutter/material.dart";
import 'package:audioplayers/audio_cache.dart';
class Account extends StatefulWidget {
Account({Key key}) : super(key: key);
#override
_AccountState createState() => _AccountState();
}
class _AccountState extends State<Account> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Stack(
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextButton(
child: Container(
child: Text(
'One',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.red),
),
onPressed: () {
final player = AudioCache();
player.play('note1.wav');
},
),
SizedBox(
height: 1,
),
TextButton(
child: Container(
child: Text(
'Two',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.green),
),
onPressed: () {
final player = AudioCache();
player.play('note2.wav');
},
),
TextButton(
child: Container(
child: Text(
'Three',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.blue),
),
onPressed: () {
final player = AudioCache();
player.play('note3.wav');
},
),
TextButton(
child: Container(
child: Text(
'Four',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.grey),
),
onPressed: () {
final player = AudioCache();
player.play('note4.wav');
},
),
TextButton(
child: Container(
child: Text(
'Five',
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.purple),
),
onPressed: () {
final player = AudioCache();
player.play('note5.wav');
},
),
],
),
),
],
),
),
),
);
}
}
You just wrap your text button with the SizedBox and set height and width as follows:
SizedBox(
height: 30,
width: 150,
child: TextButton(...),
)
Full available height:
SizedBox(
height: double.infinity, // <-- match_parent
child: TextButton(...)
)
Specific height:
SizedBox(
height: 100, // <-- Your height
child: TextButton(...)
)
In Flutter 2.0, you can set the height of the TextButton directly without depending on other widgets by changing the ButtonStyle.fixedSize:
TextButton(
child: Text('Text Button'),
style: TextButton.styleFrom(fixedSize: Size.fromHeight(150)),
),
If you want to modify all TextButtons, put it in the ThemeData like below:
return MaterialApp(
theme: ThemeData(
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(fixedSize: Size.fromHeight(150)),
),
),
Live Demo
use the following to even add your preferred size as well
N/B: child sized box is the main child widget inside Padding widget
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30.0),
child: SizedBox(
height: 60,
width: 200,
child: ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegistrationMenu()));
},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red.shade800),
),
icon: Icon(Icons.person_add_alt_1_rounded, size: 18),
label: Text("Register Users"),
),
),
),
],
),
Wrap the TextButton in an "Expanded" Widget.
Expanded(
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.red,
padding: EdgeInsets.zero,
),
child: const Text(''),
onPressed: () {
playSound(1);
},
),
),
Another solution would be wrapping with ConstrainedBox and using minWidth & minHeight
properties.
ConstrainedBox(
constraints:BoxConstraints(
minHeight:80,
minWidth:200
),
child:TextButton(..)
)
You need to do two things
Determine text button height using
Sizedbox
Remove padding around text button using
TextStyle.StyleFrom()
SizedBox(
height: 24.0,
child: TextButton(
onPressed: () {},
child: Text('See more'),
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
),
),
),
TextButton(
onPressed: _submitOrder,
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Text("Raise")),
style: ButtonStyle(
shape: MaterialStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
side: BorderSide(color: Colors.green)))),
)
TextButton(
style: ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap
),
child: Text(''),
);
It's been a while since I've been blocking backtracking on my flutter application, I tried the Navigator.pop (context) but I still ran into a black screen, I searched the forums for success but I'm still stuck. I want that when I click on return that it brings me back to my previous page without initializing the page
import 'package:MerchantIsland/log/database.dart';
import 'package:MerchantIsland/pages/home.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class productPage extends StatefulWidget {
final String productId;
const productPage({Key key, this.productId}) : super(key: key);
#override
_productPageState createState() => _productPageState();}
class _productPageState extends State<productPage> {
#override
Widget build(BuildContext context) {
ProductService productService = ProductService();
return WillPopScope(
onWillPop: (){
MovetoPreviousScreen();},
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
MovetoPreviousScreen();
},
),
centerTitle: true,
title: Text(
'Merchant island',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
body: Stack(
children: [
FutureBuilder(
future: productService.ProductData.doc(widget.productId).get(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
if(snapshot.connectionState==ConnectionState.done){
Map<String, dynamic> documentData=snapshot.data.data();
return ListView(
children: [
Container(
height: 400.0,
child: Image.network(
"${documentData['pictures'][0]}",
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0,horizontal: 24.0),
child: Text('${documentData['productName']}'??"Nom du produit",
style:TextStyle(
fontSize: 28.0,
fontWeight: FontWeight.bold,
) ,),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0,horizontal: 24.0),
child: Text('${documentData['price']}',
style:TextStyle(
fontSize: 22.0,
fontWeight: FontWeight.bold,
color:Colors.red
) ),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0,horizontal: 24.0),
child: Text('${documentData['description']}',
style:TextStyle(
fontSize: 18
) ),
)
],
);
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}),
],
),
),
); }
// ignore: non_constant_identifier_names
void MovetoPreviousScreen() {
Navigator.of(context).pop(); }}
return page
import 'package:MerchantIsland/log/database.dart';
import 'package:MerchantIsland/log/loginUI.dart';
import 'package:MerchantIsland/pages/Sellproduct.dart';
import 'package:MerchantIsland/pages/bidPage.dart';
import 'package:MerchantIsland/products/productPage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:MerchantIsland/pages/profil.dart';
import 'package:MerchantIsland/pages/balance.dart';
import 'package:MerchantIsland/pages/Settings.dart';
import 'package:google_sign_in/google_sign_in.dart';
// ignore: camel_case_types
class home extends StatefulWidget {
#override
_homeState createState() => _homeState();}
// ignore: camel_case_types
class _homeState extends State<home> {
ProductService productService = ProductService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text("Merchant Island"),
actions: [
IconButton(
icon: Icon(Icons.search, color: Colors.white,), onPressed: null,),
],
),
body: Stack(
children: [
FutureBuilder<QuerySnapshot>(
future: productService.ProductData.get(),
builder:(context,snapshot){
if(snapshot.hasError){
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
if(snapshot.connectionState==ConnectionState.done){
return Container(
child: ListView(
children: snapshot.data.docs.map((documents){
return Container(
child: GestureDetector(
onTap: (){
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>productPage(productId: documents.id,)));
},
child: Container(
child: productCard(documents.data()["productName"],documents.data()["category"], documents.data()["price"],documents.data()["pictures"]) ,
),
),
);
}).toList(),
),
);
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}),
],
),
drawer: BDrawer(context),
); }}
// ignore: non_constant_identifier_names
Drawer BDrawer(BuildContext context) {
FirebaseAuth _auth = FirebaseAuth.instance;
GoogleSignIn _googleSignIn = GoogleSignIn();
Future <void> signOut() async {
await _auth.signOut();
await _googleSignIn.disconnect();
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => LoginUI()));}
return Drawer(
child: ListView(
children: [
UserAccountsDrawerHeader(
accountName: Text('TITAN', style: TextStyle(
fontSize: 18.0,
),),
accountEmail: Text('philippetankoano#gmail.com'),
currentAccountPicture: GestureDetector(
child: CircleAvatar(
backgroundColor: Colors.grey,
child: Icon(
Icons.person, color: Colors.white
),
),
),
otherAccountsPictures: [
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => profil(),)),
child: (
Icon(
Icons.mode_edit, size: 30.0,
)
),
)
],
),
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => balancepage())),
child: ListTile(
leading: Icon(
Icons.account_balance, size: 30.0, color: Colors.blue,),
title: Text(' Balance', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => home())),
child: ListTile(
leading: Icon(Icons.home, size: 30.0, color: Colors.blue,),
title: Text(' Home', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SellProduct())),
child: ListTile(
leading: Icon(
Icons.account_balance, size: 30.0, color: Colors.blue,),
title: Text(' Sell product', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () {},
child: ListTile(
leading: Icon(
Icons.shopping_basket_outlined, size: 40.0,
color: Colors.blue,),
title: Text('Sale', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () {},
child: ListTile(
leading: Icon(Icons.category, size: 30.0, color: Colors.blue,),
title: Text(' Categories', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => bidPage())),
child: ListTile(
leading: Icon(
Icons.event_available, size: 40.0, color: Colors.blue,),
title: Text(' Bid', style: TextStyle(
fontSize: 18.0,
),),
),
),
Divider(),
InkWell(
onTap: () =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Settingpage(),)),
child: ListTile(
leading: Icon(Icons.settings, size: 30.0, color: Colors.blue,),
title: Text(' Setting', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () {},
child: ListTile(
leading: Icon(Icons.help, size: 30.0, color: Colors.blue,),
title: Text(' Help', style: TextStyle(
fontSize: 18.0,
),),
),
),
InkWell(
onTap: () async {
signOut();
},
child: ListTile(
leading: Icon(Icons.exit_to_app, size: 30.0, color: Colors.blue,),
title: Text(' Deconnexion', style: TextStyle(
fontSize: 18.0,
),),
),
),
]
), );}
Padding productCard(String name,String category,String price,List imageUrl){
return Padding(
padding: const EdgeInsets.all(6.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(-2,-1),
blurRadius: 5
)
] ),
child: GestureDetector(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(7.0),
child: Image.network(
"${imageUrl[0]}",
height: 500,
width: 450,
),
),
],
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(' $name ',style: TextStyle(fontSize: 24.0,fontWeight: FontWeight.bold)),
Text('$price ',style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.bold,color: Colors.red)),
],
),
),
Text('Categorie: $category \n',style: TextStyle(fontSize: 24.0,)),
],
),
), ),);}
Method One(Recommended)
First check if there is more than one Material App in your project if found then remove all except the root one (Child of MyApp) if that does not work or you have only one MaterialApp in your project then only try second method
Method Two(Try only if method one doesn't solved your issue or you don't have more than one MaterialApp in your project)
Replace Navigator.of(context).pop(); with Navigator.of(context,rootNavigator:true).pop(context)
If you got a black screen, it's probably because you are popping the only screen in your stack.
If you want that Navigator.of(context).pop() remove only the last screen, you have to display the current screen with a Navigator.of(context).push()
When clicking on the custom back icon Leading with in flutter
Replace Navigator.of(context).pop(); with Navigator.of(context,rootNavigator:true).pop(context)
appBar: AppBar(
automaticallyImplyLeading: true,
backgroundColor: ColorConstants.kBlackColor,
leading: BackButton(
color: ColorConstants.kWhiteColor,
onPressed: (){
Navigator.of(context,rootNavigator:true).pop(context);
},
),
),
In my case the problem was having some Navigator.pop(context) inside other callback functions.
When I clicked the back button, a socket would close, and consequently call the callback function (that also called pop()), so I would have Navigator.pop(context) called more than one time. And since my Page widget was the second element of the stack, calling it 2 times would pop also the root, therefore generating the black screen.
What I did to fix it, even though I think there might be better solutions, was substituting all the Navigator.pop(context) calls with the following:
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
Another possible solution would be to initialize a bool variable (or a some kind of counter) and then call pop() only if that variable is true, then set it to false.:
// init
bool variable = true;
if (variable) {
Navigator.pop(context);
variable = false;
}