I need to display checkboxes selected by the user on the previous page using pop() I have a function that displays the user's message on the previous page and I need to pass the selected checkboxes in the same way. How to pass them as arguments to pop()? Screen with checkboxes:
const TextScreen({Key? key}) : super(key: key);
@override
State<TextScreen> createState() => _TextScreenState();
}
class _TextScreenState extends State<TextScreen> {
// initial values for checkboxes
bool _privacy = false;
bool _termsOfUse = false;
// text controller for message input
TextEditingController textController = TextEditingController();
@override
void dispose() {
textController.dispose();
super.dispose();
}
// go to result screen
void getResult(BuildContext context) {
String valueResult = textController.text;
Navigator.pop(context, valueResult);
}
@override
Widget build(BuildContext context) {
//change state for privacy checkbox
_onPrivacyChange(value) {
setState(() {
_privacy = value!;
});
}
//change state for terms of use checkbox
_onTermsOfUSeChange(value) {
setState(() {
_termsOfUse = value!;
});
}
return Scaffold(
appBar: AppBar(
title: const Text('Enter data'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: textController,
decoration: const InputDecoration(labelText: 'Message')),
const SizedBox(height: 20),
CheckboxListTile(
title: const Text('Privacy'),
controlAffinity: ListTileControlAffinity.leading,
value: _privacy,
onChanged: _onPrivacyChange,
contentPadding: EdgeInsets.zero,
),
CheckboxListTile(
title: const Text('Terms of use'),
controlAffinity: ListTileControlAffinity.leading,
value: _termsOfUse,
onChanged: _onTermsOfUSeChange,
contentPadding: EdgeInsets.zero,
),
ElevatedButton(
onPressed: () {
getResult(context);
},
child: const Text('Display result'))
],
)),
);
}
}
Screen with results display:
class ResultScreen extends StatefulWidget {
const ResultScreen({Key? key}) : super(key: key);
@override
State<ResultScreen> createState() => _ResultScreenState();
}
class _ResultScreenState extends State<ResultScreen> {
String? _valueText = '';
@override
Widget build(BuildContext context) {
// navigation to next screen
void _navToNextScreen(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TextScreen()),
);
// update widget after result comes back
setState(() {
_valueText = result;
});
}
return Scaffold(
appBar: AppBar(
title: const Text('Results'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
_navToNextScreen(context);
},
child: const Text('Enter data'),
),
const SizedBox(height: 50),
Text('Message: $_valueText'),
const SizedBox(height: 20),
Text('Checkboxes: '),
],
)),
);
}
}
CodePudding user response:
I think this should be the job of a simple state management strategy; for communication between separate widgets (in this case, two page widgets), that's the cleanest approach. You should create a common service to which both page widgets are subscribed: one to trigger the changes, the other to capture them and display them, using a ChangeNotifier service along with Consumer widgets, as shown below:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => SelectedData(),
child: MyApp()
)
);
}
class SelectedData extends ChangeNotifier {
bool _privacy = false;
bool _termsOfUse = false;
String _valueResult = '';
bool get privacy => _privacy;
bool get termsOfUse => _termsOfUse;
String get valueResult => _valueResult;
set privacy(bool value) {
_privacy = value;
notifyListeners();
}
set termsOfUse(bool value) {
_termsOfUse = value;
notifyListeners();
}
set valueResult(String value) {
_valueResult = value;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: ResultScreen(),
),
),
);
}
}
class TextScreen extends StatefulWidget {
const TextScreen({Key? key}) : super(key: key);
@override
State<TextScreen> createState() => _TextScreenState();
}
class _TextScreenState extends State<TextScreen> {
// text controller for message input
TextEditingController textController = TextEditingController();
@override
void initState() {
super.initState();
}
@override
void dispose() {
textController.dispose();
super.dispose();
}
// go to result screen
void getResult(BuildContext context) {
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
SelectedData data = Provider.of<SelectedData>(context, listen: false);
textController.text = data.valueResult;
//change state for privacy checkbox
_onPrivacyChange(value) {
data.privacy = value;
}
//change state for terms of use checkbox
_onTermsOfUSeChange(value) {
data.termsOfUse = value;
}
return Scaffold(
appBar: AppBar(
title: const Text('Enter data'),
),
body: Consumer<SelectedData>(
builder: (context, selectedData, child) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: textController,
onChanged: (value) {
data.valueResult = value;
},
decoration: const InputDecoration(labelText: 'Message')),
const SizedBox(height: 20),
CheckboxListTile(
title: const Text('Privacy'),
controlAffinity: ListTileControlAffinity.leading,
value: selectedData.privacy,
onChanged: _onPrivacyChange,
contentPadding: EdgeInsets.zero,
),
CheckboxListTile(
title: const Text('Terms of use'),
controlAffinity: ListTileControlAffinity.leading,
value: selectedData.termsOfUse,
onChanged: _onTermsOfUSeChange,
contentPadding: EdgeInsets.zero,
),
ElevatedButton(
onPressed: () {
getResult(context);
},
child: const Text('Display result'))
],
));
}
),
);
}
}
class ResultScreen extends StatefulWidget {
const ResultScreen({Key? key}) : super(key: key);
@override
State<ResultScreen> createState() => _ResultScreenState();
}
class _ResultScreenState extends State<ResultScreen> {
@override
Widget build(BuildContext context) {
// navigation to next screen
void _navToNextScreen(BuildContext context) async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TextScreen()),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Results'),
),
body: Consumer<SelectedData>(
builder: (context, selectedData, child) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
_navToNextScreen(context);
},
child: const Text('Enter data'),
),
const SizedBox(height: 50),
Text('Message: ${selectedData.valueResult}'),
const SizedBox(height: 20),
const Text('Checkboxes: '),
Text('Privacy: ${selectedData.privacy}'),
Text('Terms of Use: ${selectedData.termsOfUse}')
],
));
}
),
);
}
}
Here's the output when you implement it this way:
CodePudding user response:
So from what i see is you are only passing one value that is message and you what many values to pass at a time so here the map can be used and as pop() function takes dynamic returns you can pass any thing.
From your example i have created a sample example that will be a working proof which will demostrate the using map for passing data to previous screen.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: ResultScreen(),
);
}
}
class TextScreen extends StatefulWidget {
const TextScreen({Key? key}) : super(key: key);
@override
_TextScreenState createState() => _TextScreenState();
}
class _TextScreenState extends State<TextScreen> {
// initial values for checkboxes
bool _privacy = false;
bool _termsOfUse = false;
// text controller for message input
TextEditingController textController = TextEditingController();
@override
void dispose() {
textController.dispose();
super.dispose();
}
// go to result screen
void getResult(BuildContext context) {
String valueResult = textController.text;
final data = {
"message":valueResult,
"privacy": _privacy,
'terms':_termsOfUse,
};
Navigator.pop(context, data);
}
@override
Widget build(BuildContext context) {
//change state for privacy checkbox
_onPrivacyChange(value) {
setState(() {
_privacy = value!;
});
}
//change state for terms of use checkbox
_onTermsOfUSeChange(value) {
setState(() {
_termsOfUse = value!;
});
}
return Scaffold(
appBar: AppBar(
title: const Text('Enter data'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: textController,
decoration: const InputDecoration(labelText: 'Message')),
const SizedBox(height: 20),
CheckboxListTile(
title: const Text('Privacy'),
controlAffinity: ListTileControlAffinity.leading,
value: _privacy,
onChanged: _onPrivacyChange,
contentPadding: EdgeInsets.zero,
),
CheckboxListTile(
title: const Text('Terms of use'),
controlAffinity: ListTileControlAffinity.leading,
value: _termsOfUse,
onChanged: _onTermsOfUSeChange,
contentPadding: EdgeInsets.zero,
),
ElevatedButton(
onPressed: () {
getResult(context);
},
child: const Text('Display result'))
],
)),
);
}
}
class ResultScreen extends StatefulWidget {
const ResultScreen({Key? key}) : super(key: key);
@override
State<ResultScreen> createState() => _ResultScreenState();
}
class _ResultScreenState extends State<ResultScreen> {
String? _valueText = '';
bool _privacyValue =false;
bool _termsOfUse = false;
@override
Widget build(BuildContext context) {
// navigation to next screen
void _navToNextScreen(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TextScreen()),
);
if(result !=null)
{
setState(() {
if(result['message']!=null )_valueText = result['message'];
if(result['privacy']!=null) _privacyValue = result['privacy'];
if(result['terms']!=null) _termsOfUse = result['terms'];
});
}
}
return Scaffold(
appBar: AppBar(
title: const Text('Results'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
_navToNextScreen(context);
},
child: const Text('Enter data'),
),
const SizedBox(height: 50),
Text('Message: $_valueText'),
const SizedBox(height: 20),
Text('Privacy Value: $_privacyValue '),
const SizedBox(height: 20),
Text('Terms Value: $_termsOfUse '),
],
)),
);
}
}
You can make changes as per your needs, So let me know if it works.