I’m new to learning flutter and am learning about navigation. I have two screens in my app. The first screen has a button which pushes a named route along with arguments to the second screen. The second screen displays the arguments and when the back button on the appBar is pressed, I want the first screen to completely rebuild. I tried popping the first screen and then pushing it again and that causes some misbehaviors. Is there any other way?
I tried using .then method and setting the state again in it, but that does not work as well. Here’s the problem I’m facing:
The number should start from 1 but it just shows 1 and on increment it does not show 2. Here’s the code to reproduce the result:
import 'package:flutter/material.dart';
import 'package:uistepper/uistepper.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(useMaterial3: true),
routes: {
'/list_screen': (ctx) => const NextScreen(),
},
home: Scaffold(
appBar: AppBar(
title: const Text('Practice App'),
),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
double noOfItems = 1;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Choose number of list view items:'),
SizedBox(
height: 75,
child: Center(
child: Text(noOfItems.round().toString()),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
UIStepper(
value: noOfItems,
stepValue: 1,
onChanged: (double newValue) {
setState(() {
noOfItems = newValue;
});
},
showLabel: false,
),
],
),
const SizedBox(height: 100),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/list_screen',
arguments: noOfItems.round(),
).then((_) => setState(() {
noOfItems = 1;
}));
},
child: const Text('Go'),
),
],
),
);
}
}
class NextScreen extends StatefulWidget {
const NextScreen({super.key});
@override
State<NextScreen> createState() => _NextScreenState();
}
class _NextScreenState extends State<NextScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListView with ${getNoOfItems(ctx: context)} entries'),
),
body: ListView.separated(
itemBuilder: (BuildContext context, int index) {
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text('Item ${index + 1}'),
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemCount: getNoOfItems(ctx: context),
),
);
}
}
int getNoOfItems({required BuildContext ctx}) {
String strNum = (ModalRoute.of(ctx)?.settings.arguments).toString();
int number = int.parse(strNum);
return number;
}
For UIStepper(version: 0.0.2) I’m using the package: https://pub.dev/packages/uistepper
I am running the code on simulator.
2
Answers
The behavior of the back button on a screen depends on the platform or framework you’re using for development.
This is actually a very common task.
To rebuild the First screen after the second screen was popped, you can do the following:
Assuming that you are using
Navigator.push
to push a new screen onto the stack,Navigator.push
returns aFuture
after popping from the second screen. so just use.then()
and callsetState
:Here is complete working example, it will update the counter variable (and UI) on the first screen everytime you push from the second screen: