I have a flutter app (full code below) that displays a list, whose items are selectable independently of each other, and a status bar that displays the number of items selected.
Whenever an item in the list is tapped, its selected property is toggled, the setter invokes notifyListeners, and the check mark also toggles because the list tile is rebuilt thanks to provider.
But the item counter in the statusbar doesn't change. This is understandable since nobody's invoking notifyListeners on the global app state.
So my question is: how can I propagate a change in a part of the app state upwards if this change has to trigger the rebuild of other widgets?
I could write a method in AppState that toggles the item itself and then calls notifyListeners on AppState, but this doesn't sound like a good solution.
Full source code:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Item extends ChangeNotifier {
bool _selected = false;
final String label;
Item(this.label);
set selected(bool s) {
_selected = s;
notifyListeners();
}
bool get selected => _selected;
}
class AppState extends ChangeNotifier {
List<Item> items = [
Item("Apple"),
Item("Banana"),
Item("Peach"),
Item("Strawberry")
];
}
void main() {
runApp(ChangeNotifierProvider(
create: (context) => AppState(), child: const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Consumer<AppState>(
builder: (context, appState, _) => Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: appState.items
.map((e) => ChangeNotifierProvider.value(
value: e,
builder: (context, _) => const ItemWidget()))
.toList(),
),
),
bottomSheet: BottomSheet(
builder: (context) => Container(
padding: const EdgeInsets.all(20),
child: Text(
"${appState.items.where((element) => element.selected).length}"
" items selected"),
),
onClosing: () {},
),
));
}
}
class ItemWidget extends StatelessWidget {
const ItemWidget({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
child: Consumer<Item>(
builder: (context, item, _) => ListTile(
leading: Icon(item.selected ? Icons.check_circle : Icons.circle),
title: Text(item.label),
onTap: () => item.selected = !item.selected,
),
),
);
}
}
Related
I am trying to use hive to store data on a local machine using hive but each time when I compile the code it gives the error "The box "notebook" is already open and of type Box."
Can someone help me to resolve the issue as I am new to it? Thanks
I am just trying to add data to the database in this app without any change to the state of the app interface. I have tried to change the main method to void but no luck on this.
All the code is located in the main file
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'notes.dart';
import 'notesStoring.dart';
Future main() async{
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(NotesAdapter());
await Hive.openBox<NotesAdapter>('noteBook');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void dispose() {
Hive.close();
// TODO: implement dispose
super.dispose();
}
#override
Future incrementCounter(String title) async {
final notes = Notes()
..title = title;
final box =Boxes.getNotesValues();
box.add(notes);
}
final titleForNotes=TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body:
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
TextField(
controller: titleForNotes,
cursorColor: Colors.pink,
),
ValueListenableBuilder<Box<Notes>>(valueListenable: Boxes.getNotesValues().listenable(), builder: (context,box,_){
final noteBook =box.values.toList().cast<Notes>();
return buildContent(noteBook);
})
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
incrementCounter(titleForNotes.text);
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class Boxes {
static Box<Notes> getNotesValues()=>Hive.box<Notes>('noteBook');
}
Widget buildContent(List<Notes> noteBook){
return Column(
children: [
Expanded(child:
ListView.builder(
padding: EdgeInsets.all(8),
itemCount: noteBook.length,
itemBuilder: (BuildContext context, int index){
final notes= noteBook[index];
return buildTransaction(context, notes);
}
)
)
],
);
}
Widget buildTransaction(
BuildContext context,
Notes notes,
){
return Card(
color: Colors.green,
child: Text(notes.title),
);
}
1.You can open your notebook Box in the main method of your app:
Future<void> main() async {
...
final appDocumentDirectory = await
path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(UserAdapter());
// open the user box
await Hive.openBox('notebook');
_setUpLogging();
runApp(MultiProvider(providers: providers, child:
StartupApplication()));
}
2 Access the previously opened box like below:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// user box
Box notebookBox;
#override
void initState() {
super.initState();
// get the previously opened user box
notebookBox = Hive.box('notebook');
}
#override
Widget build(BuildContext context) {
// check for your conditions
return (notebookBox.values.isNotEmpty && notebookBox.get(0).active == 1)
? HomeView()
: Intro();
}
}
I have a simple app with two screens. The first screen is a scrollable ListView and the second screen is basically empty and transparent. If I pushed the second screen with Navigator.push() on top of the first screen I'd like to be able to scroll the underlying first screen.
Here is my code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatelessWidget {
const Foo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
);
}
}
How can scroll the list in the backgound while the second screen is in the foreground?
Although this is not a solution with a second screen, it creates a similar effect using the Stack and IgnorePointer widgets:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _applyOverlay = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: _applyOverlay
? IconButton(
icon: Icon(
Icons.arrow_back_ios_sharp,
),
onPressed: () => setState(
() => _applyOverlay = false,
),
)
: null,
title: Text(_applyOverlay ? 'Overlay active' : widget.title),
),
body: Stack(
children: [
ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
if (_applyOverlay)
// Wrap container (or your custom widget) with IgnorePointer to ignore any user input
IgnorePointer(
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.white.withOpacity(0.5),
),
),
],
),
floatingActionButton: _applyOverlay
? null
: FloatingActionButton(
onPressed: () {
setState(() => _applyOverlay = true);
},
child: Icon(Icons.add),
),
);
}
}
I found a solution that works even with two screens. The idea is to have two ScrollControllers each in one screen and add a listener the ScrollController in the overlay that triggers the ScrollController of the underlying widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
const INITIAL_OFFSET = 5000.0;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
final ScrollController controller = ScrollController(
initialScrollOffset: INITIAL_OFFSET,
);
#override
void initState(){
super.initState();
controller.addListener(() {
widget.controller.animateTo(
controller.offset - INITIAL_OFFSET,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: SingleChildScrollView(
controller: controller,
child: Container(
height: 2 * INITIAL_OFFSET,
color: Colors.white.withOpacity(0.5),
),
),
);
}
}
There are still a few problems with this workaround:
This does not work for infinite lists.
The scroll behavior is bad because the background is only scrolled when the scroller ends his gesture by put the finger up.
The sizes of the both screens doesn't match. That leads to bad effects like scrolling in areas that doesn't exists in the other screen.
I finally found a satisfying answer that does not contain any kind of dirty workarounds. I use a Listener in the second screen to detect OnPointerMoveEvents which are basically scroll events.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: Listener(
onPointerMove: (event){
var newPosition = widget.controller.position.pixels - event.delta.dy;
widget.controller.jumpTo(newPosition);
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.red.withOpacity(0.5),
),
),
);
}
}
I'm trying to find a simple and clean way to manage my state in Flutter without using third party libraries. I chose to use ValueNotifier in combination with ValueListenableBuilder in order to be selective about what's being rebuilt in my app when changes occurs.
I've created a class to expose my state values using static variables so they can be used and get directly updated from anywhere without having to do any complicated gymnastic. I'm not sure it is a good practice (it looks to easy in comparison to other state management solutions) but it works.
Could you tell me why this potentially wouldn't be a viable solution?
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final CounterState _counterState = CounterState();
#override
Widget build(BuildContext context) {
final count = _counterState.counter;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
ValueListenableBuilder(
valueListenable: _counterState.counter,
builder: (BuildContext context, int count, _) => Text(
'parent count: $count',
style: Theme.of(context).textTheme.headline4,
)),
const ChildWidget()
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => count.value++,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class ChildWidget extends StatefulWidget {
const ChildWidget({Key? key}) : super(key: key);
#override
State<ChildWidget> createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
final CounterState _counterState = CounterState();
#override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: _counterState.counter,
builder: (BuildContext context, int count, _) => Center(
child: Text(
'child count: $count',
style: Theme.of(context).textTheme.headline4,
),
),
);
}
}
class CounterState {
static final ValueNotifier<int> _counter = ValueNotifier<int>(0);
ValueNotifier<int> get counter => _counter;
}
Even after reading this and this, I still can't seem to wrap my head around storing page states in Flutter.
I've built a sample app, which has a main page called MyHomePage and a second page called SecondPage. MyHomePage has a floating action button, which displays SecondPage via Navigator.push(...). The second page contains a text field with an assigned controller. I would like to preserve the text field's text after I close and reopen SecondPage.
I've tried all sorts of combinations with setting buckets, page states and keys (inspired by the links above), but I couldn't make it work.
Also I'd like to store the whole page state automatically - without the need to write/retrieve every single value manually (in case I have a lot of text fields on the page).
Here is my code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
PageStorageKey mykey = new PageStorageKey("testkey");
class MyApp extends StatelessWidget {
final PageStorageBucket _bucket = new PageStorageBucket();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PageStorage(
bucket: _bucket,
child: MyHomePage(),
)
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("State demo"),
),
body: Center(
child: Column(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openSecondPage,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_openSecondPage() {
Navigator.push(context, new MaterialPageRoute(builder: (context) => new SecondPage()));
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
final _aController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second page"),
),
body: Center(
child: TextField(
controller: _aController,
key: mykey,
autofocus: true,
),
)
);
}
}
EDIT:
Based on Ajay's answer, I was able to greatly simplify the working code. Turns out that in order to persist widget states manually, all you need is an instance of PageStorageBucket in combination with ValueKey instances.
Here are the modifications I did to Ajay's code:
Removed the after_layout plugin (initState method is sufficient).
Removed the global PageStorageKey instance (replaced it with a local ValueKey instance in the page that needs to use it).
Removed global instance of PageStorageBucket and replaced it with a final instance in MyApp, which is passed to the pages that need it via constructor attributes.
Removed PageStorage from the component tree.
Here is the resulting code (simplest working form):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final bucket = PageStorageBucket();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(bucket: bucket,),
);
}
}
class MyHomePage extends StatefulWidget {
final PageStorageBucket bucket;
const MyHomePage({Key key, this.bucket}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("State demo"),
),
body: Center(
child: Column(
children: <Widget>[],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openSecondPage,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_openSecondPage() {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => new SecondPage(bucket: widget.bucket,)));
}
}
class SecondPage extends StatefulWidget {
final PageStorageBucket bucket;
const SecondPage({Key key, this.bucket}) : super(key: key);
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
static const KEY_A = ValueKey("secondPage.A");
final _aController = TextEditingController();
#override
void initState() {
super.initState();
_aController.addListener(_updateValue);
String value = widget.bucket.readState(context, identifier: KEY_A) ?? "";
_aController.text = value;
}
_updateValue() {
widget.bucket.writeState(context, _aController.text, identifier: KEY_A);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second page"),
),
body: Center(
child: TextField(
controller: _aController,
autofocus: true,
),
),
);
}
}
you need to read and write the state as well.
Check out the below code.
Note: I have used after_layout to initialize the text controller.
import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
PageStorageKey mykey = new PageStorageKey("testkey");
final PageStorageBucket _bucket = new PageStorageBucket();
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PageStorage(
bucket: _bucket,
child: MyHomePage(),
));
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("State demo"),
),
body: Center(
child: Column(
children: <Widget>[],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openSecondPage,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
_openSecondPage() {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => new SecondPage()));
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage>
with AfterLayoutMixin<SecondPage> {
final _aController = TextEditingController();
#override
void initState() {
super.initState();
_aController.addListener(_updateValue);
}
#override
void afterFirstLayout(BuildContext context) {
String value =
_bucket.readState(context, identifier: ValueKey(mykey)) ?? "";
print(value);
_aController.text = value;
}
_updateValue() {
_bucket.writeState(context, _aController.text, identifier: ValueKey(mykey));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second page"),
),
body: Center(
child: TextField(
controller: _aController,
key: mykey,
autofocus: true,
),
),
);
}
}
While passing an object from one class to another class by using Navigator.push(), the object does not get modifying even its declared as not final.
Main Screen : Created an object(userBean) and passing to First screen
First Screen : displaying the same object(userBean) values, and passing again the same object(userBean) to second screen.
Second screen : trying to get modify the same object (userBean) in second screen, and printing the same object(userBean) in first screen by using refreshData.then method.
Main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_poc1/firstSceeen.dart';
import 'package:flutter_app_poc1/secondScreen.dart';
import 'package:flutter_app_poc1/userbean.dart';
void main() => runApp(MyApp());
typedef void refreshCallBack(int index);
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
UserBean user = new UserBean();
final List<String> hhList = ["General", "edu"];
int _counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new FlatButton(
child: Text("Next Screen"),
onPressed: () {
user.id = 1;
user.name = "Ramesh";
Future<dynamic> refreshData =
Navigator.of(context).push(new MaterialPageRoute<dynamic>(
builder: (BuildContext context) {
return new FirstScreen(userbean: user);
},
));
refreshData.then((_) {
});
}),
],
),
),
);
}
}
Firstscreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_poc1/secondScreen.dart';
import 'package:flutter_app_poc1/userbean.dart';
typedef void refreshCallBack(int index);
class FirstScreen extends StatefulWidget {
UserBean userbean;
FirstScreen({Key key, this.userbean}) : super(key: key);
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
String userName;
final List<String> hhList = ["General", "edu"];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("first"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(widget.userbean.name),
new RaisedButton(onPressed: (){
Future<dynamic> refreshData =
Navigator.of(context).push(new MaterialPageRoute<dynamic>(
builder: (BuildContext context) {
return new SecondScreen(userbean: widget.userbean);
},
));
refreshData.then((_) {
print(widget.userbean.name);
});
}),
],
),
),
);
}
}
secondscreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_app_poc1/userbean.dart';
class SecondScreen extends StatefulWidget {
UserBean userbean;
SecondScreen({Key key, this.userbean}) : super(key: key);
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
UserBean bean = UserBean();
#override
Widget build(BuildContext context) {
bean.name = "suresh";
return Scaffold(
appBar: AppBar(
title: Text("Previous Screen"),
),
body: Center(
child: new FlatButton(
child: Text(bean.name),
onPressed: () {
print(bean.name);
widget.userbean = bean;
Navigator.pop(context, true);
}),
));
}
}
#Murali
If you want to follow the same procedure pass object, then follow the below procedure.
From Navigator.pop push again new Object
onPressed: () {
print("TEST second screen :"+bean.name);
/// here modifying with new object.
widget.userbean = bean;
Navigator.pop(context, widget.userbean);
}),
In second screen Get new Object from Feature Method as below
Future<UserBean> refreshData =
Navigator.of(context).push(new MaterialPageRoute<UserBean>(
builder: (BuildContext context) {
return new SecondScreen(userbean: widget.userbean);
},
));
refreshData.then((res) {
print("TEST First screen : ${res.name}");
});
Then Object will change with new values.