Home > Software engineering >  How to show selected checkbox on prev screen?
How to show selected checkbox on prev screen?

Time:05-03

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:

enter image description here

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.

  • Related