flutterdartflutter-pageview

How to pass data from two dropdown buttons between pages in PageView Widget?


I am building an onboarding feature with three pages:

Page 0:

class Page0 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _Page0State();
}

class _Page0State extends State<Page0> {
  late UserPreferencesArguments? args;

  int currentPage = 0;
  static const _kDuration = const Duration(milliseconds: 500);
  static const _kCurve = Curves.ease;
  PageController pageController = PageController();
  final globalScaffoldKey = GlobalKey<ScaffoldState>();

  List<Widget> widgets = [];

  @override
  void initState() {
    super.initState();
    init();
  }

  init() async {
    widgets.add(Page1());
    widgets.add(Page2());
  }

  @override
  void dispose() {
    //pageController?.dispose();
    super.dispose();
  }

  @override
  void setState(fn) {
    if (mounted) super.setState(fn);
  }

  @override
  Widget build(BuildContext context) {
    args = ModalRoute.of(context)?.settings.arguments as UserPreferencesArguments?;

    return SafeArea(
      child: Scaffold(
        key: globalScaffoldKey,
        body: Stack(
          children: [
            Container(
              child: PageView(
                scrollDirection: Axis.horizontal,
                controller: pageController,
                children: widgets,
                onPageChanged: (i) {
                  currentPage = i;
                  setState(() {});
                },
              ),
            ),
            Positioned(
              child: Container(
                child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.black,
                    shadowColor: Colors.grey,
                  ),
                  onPressed: () {
                    if (currentPage == 1) {
                      updateAttributes(args?.aaa, args?.bbb);
                      Navigator.pushReplacementNamed(context, '/homepage');
                    } else {
                      pageController.nextPage(duration: _kDuration, curve: _kCurve);
                    }
                  },
                  child: Text(currentPage == 1 ? 'Finish' : "Next",),
                ),
              ),
            ),
          ],
        )
      ),
    );
  }

  updateAttributes(aaa, bbb) async {
    debugPrint('devid:  ${aaa}');
    debugPrint('devid:  ${bbb}');
  }

}

Page 2:

class Page2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _Page2State();
}

class _Page2State extends State<Page2> {

  String aaaImportValue = "";
  String? _valAAA;
  List _aaaList = ["1", "2" ];

  String bbbImportValue = "";
  String? _valBBB;
  List _bbbList = ["3", "4" ];

  @override
  void initState() {
    super.initState();
    init();
  }

  init() async {}

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
                    Container(
                      child: DropdownButton<String>(
                        hint: Text("Select").tr(),
                        value: _valAAA,
                        items: _aaaList.map((value) {
                          return DropdownMenuItem<String>(
                            child: Text(value),
                            value: value,
                          );
                        }).toList(),
                        onChanged: (String? value) {
                          setState(() {
                              _valAAA = value!;
                          });
                        },
                      ),
                    ),
                    Container(
                      child: DropdownButton<String>(
                        hint: Text("Select").tr(),
                        value: _valBBB,
                        items: _bbbList.map((value) {
                          return DropdownMenuItem<String>(
                            child: Text(value),
                            value: value,
                          );
                        }).toList(),
                        onChanged: (String? value) {
                          setState(() {
                            _valBBB = value!;
                          });
                        },
                      ),
                    ),
      ],
    );
  }
}

I tried passing the dropdown values in this way but this just navigates to Page0:

onChanged: (String? value) {
    setState(() {
         _valBBB = value!;
         if(_valBBB != null){
             Navigator.pushNamed(context, "/Page0",
             arguments: UserPreferencesArguments(_valAAA, _valBBB));
         }
    });
},

Solution

  • You can use callback method on Page2,

    class Page2 extends StatefulWidget {
      final Function(String? value1, String? value2) callback;
      const Page2({
        Key? key,
        required this.callback,
      }) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _Page2State();
    }
    

    Now value changed , call

    onChanged: (String? value) {
      setState(() {
        _valAAA = value!;
      });
    
      widget.callback(_valAAA, _valBBB);
    },
    

    And you will get value

    init() async {
      widgets.add(Page1());
      widgets.add(Page2(
        callback: (value1, value2) {
          
        },
      ));
    }
    

    Tests snippet

    class Page0 extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => new _Page0State();
    }
    
    class _Page0State extends State<Page0> {
      int currentPage = 0;
    
      PageController pageController = PageController();
      final globalScaffoldKey = GlobalKey<ScaffoldState>();
    
      List<Widget> widgets = [];
    
      @override
      void initState() {
        super.initState();
        init();
      }
    
      String? value1, value2;
    
      init() async {
        widgets.add(Text("Page1"));
        widgets.add(Page2(
          callback: (v1, v2) {
            value1 = v1;
            value2 = v2;
            log("value 1 $value1 value2 $value2");
          },
        ));
      }
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
              key: globalScaffoldKey,
              body: Stack(
                children: [
                  PageView(
                    scrollDirection: Axis.horizontal,
                    controller: pageController,
                    children: widgets,
                    onPageChanged: (i) {
                      currentPage = i;
                      setState(() {});
                    },
                  ),
                  Center(child: Text("v1 $value1, v2 $value2"))
                ],
              )),
        );
      }
    }
    
    class Page2 extends StatefulWidget {
      final Function(String? value1, String? value2) callback;
      const Page2({
        Key? key,
        required this.callback,
      }) : super(key: key);
    
      @override
      State<StatefulWidget> createState() => _Page2State();
    }
    
    class _Page2State extends State<Page2> {
      String aaaImportValue = "";
      String? _valAAA;
      List _aaaList = ["1", "2"];
    
      String bbbImportValue = "";
      String? _valBBB;
      List _bbbList = ["3", "4"];
    
      @override
      void initState() {
        super.initState();
        init();
      }
    
      init() async {}
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Container(
              child: DropdownButton<String>(
                hint: Text("Select"),
                value: _valAAA,
                items: _aaaList.map((value) {
                  return DropdownMenuItem<String>(
                    child: Text(value),
                    value: value,
                  );
                }).toList(),
                onChanged: (String? value) {
                  setState(() {
                    _valAAA = value!;
                  });
    
                  widget.callback(_valAAA, _valBBB);
                },
              ),
            ),
            Container(
              child: DropdownButton<String>(
                hint: Text("Select"),
                value: _valBBB,
                items: _bbbList.map((value) {
                  return DropdownMenuItem<String>(
                    child: Text(value),
                    value: value,
                  );
                }).toList(),
                onChanged: (String? value) {
                  setState(() {
                    _valBBB = value!;
                  });
                },
              ),
            ),
          ],
        );
      }
    }