Saturday, June 8, 2019

Pass child state to parent state in Flutter

08th June 2019,

In my recent flutter project I got a requirement to pass children states to parent state and move to the next screen based on children states.




As above image user can be select or deselect a row by clicking it. So I made a stateful widget which can be used multiple times.

 class RowContent extends StatefulWidget {  
  final String question;  
  RowContent(this.question);  
  @override  
  _RowContentState createState() => _RowContentState(question);  
 }  
 class _RowContentState extends State<RowContent> {  
  String passedQuestion;  
  var selectedImage;  
  var unSelectedImage;  
  var currentImage;  
  _RowContentState(this.passedQuestion);  
  @override  
  void initState() {  
   super.initState();  
   selectedImage = AssetImage("assets/images/ic_check.png");  
   unSelectedImage = AssetImage("assets/images/ic_uncheck.png");  
   currentImage = unSelectedImage;  
  }  
  @override  
  Widget build(BuildContext context) {  
   return InkWell(  
    onTap: () {  
     setState(() {  
      currentImage =  
        currentImage == selectedImage ? unSelectedImage : selectedImage;  
     });  
    },  
    child: Row(  
     children: <Widget>[  
      Padding(  
       padding: const EdgeInsets.only(  
        left: 32.0,  
        right: 26.0,  
       ),  
       child: Container(  
        height: 48,  
        width: 48,  
        decoration: new BoxDecoration(  
         image: new DecorationImage(  
           image: currentImage, fit: BoxFit.scaleDown),  
        ),  
       ),  
      ),  
      Expanded(  
       child: Padding(  
        padding: const EdgeInsets.only(right: 32.0),  
        child: Text(  
         passedQuestion  
        ),  
       ),  
      ),  
     ],  
    ),  
   );  
  }  
 }  

Now I want to go to the next screen only if user has selected all the 3 rows. This is where I wonder how can I pass the children states to the parent state so that parent can decide when to move to the next screen. for achive this I used callback methods.

Here is the code of parent component with callbacks.

 class OpenReport extends StatefulWidget {  
  @override  
  _OpenReportState createState() => _OpenReportState();  
 }  
 class _OpenReportState extends State<OpenReport> {  
  int totalCount = 0;  
  callback(int value){  
   setState(() {  
    totalCount = totalCount + value;  
    debugPrint(totalCount.toString());  
   });  
  }  
  @override  
  Widget build(BuildContext context) {  
   return Scaffold(  
    appBar: buildAppBar(context),  
    body: buildOpenReportContent(context),  
   );  
  }  
  AppBar buildAppBar(BuildContext context) {  
   return AppBar(  
    elevation: 0.0,  
    actions: <Widget>[  
     IconButton(  
       icon: Icon(  
        Icons.close,  
       ),  
       onPressed: () {  
        if (Navigator.canPop(context)) {  
         Navigator.pop(context, true);  
        }  
       },  
      ),  
    ],  
    centerTitle: true,  
   );  
  }  
  Widget buildOpenReportContent(BuildContext context) {  
   return Container(  
    child: Column(  
     children: <Widget>[  
      Container(  
       child: Padding(  
        padding: const EdgeInsets.only(  
         left: 80.0,  
         top: 28.0,  
         right: 80.0,  
        ),  
        child: Text(  
         "",  
         textAlign: TextAlign.center,  
        ),  
       ),  
      ),  
      Expanded(  
       child: Column(  
        children: <Widget>[  
         Padding(  
          padding: const EdgeInsets.only(top: 64.0, bottom: 32.0),  
          child: RowContent("Row 1 click to enable", callback),  
         ),  
         RowContent("Row 2 click to enable", callback),  
         Padding(  
          padding: const EdgeInsets.only(top: 32.0),  
          child: RowContent("Row 3 click to enable", callback),  
         ),  
        ],  
       ),  
      ),  
      Container(  
       child: Padding(  
        padding: const EdgeInsets.all(24.0),  
        child: Container(  
         height: 48.0,  
         child: FlatButton(  
          onPressed: () {  
           if (totalCount == 3){  
            debugPrint("implement go to next screen");  
           }  
          },  
          child: Row(  
           mainAxisAlignment: MainAxisAlignment.center,  
           children: <Widget>[  
            Text(  
             "go to next screen",  
            ),  
           ],  
          ),  
         ),  
        ),  
       ),  
      ),  
     ],  
    ),  
   );  
  }  
 }  

Here's how the child component changed.

 class RowContent extends StatefulWidget {  
  final String question;  
  final Function(int) callback; // getting the parent function  
  RowContent(this.question, this.callback);  
  @override  
  _RowContentState createState() => _RowContentState(question);  
 }  
 class _RowContentState extends State<RowContent> {  
  String passedQuestion;  
  var selectedImage;  
  var unSelectedImage;  
  var currentImage;  
  _RowContentState(this.passedQuestion);  
  @override  
  void initState() {  
   super.initState();  
   selectedImage = AssetImage("assets/images/ic_check.png");  
   unSelectedImage = AssetImage("assets/images/ic_uncheck.png");  
   currentImage = unSelectedImage;  
  }  
  @override  
  Widget build(BuildContext context) {  
   return InkWell(  
    onTap: () {  
     setState(() {  
      currentImage =  
        currentImage == selectedImage ? unSelectedImage : selectedImage;  
      widget.callback(currentImage == selectedImage ? 1 : -1); // calling parent function  
     });  
    },  
    child: Row(  
     children: <Widget>[  
      Padding(  
       padding: const EdgeInsets.only(  
        left: 32.0,  
        right: 26.0,  
       ),  
       child: Container(  
        height: 48,  
        width: 48,  
        decoration: new BoxDecoration(  
         image: new DecorationImage(  
           image: currentImage, fit: BoxFit.scaleDown),  
        ),  
       ),  
      ),  
      Expanded(  
       child: Padding(  
        padding: const EdgeInsets.only(right: 32.0),  
        child: Text(  
         passedQuestion,  
        ),  
       ),  
      ),  
     ],  
    ),  
   );  
  }  
 }  

This is how you can pass child state to parent state. There is another way to do this using global state obeject. Anyway hope someone find this useful.
Happy coding!!!


No comments:

Post a Comment