How to Change - Update the State inside Bottom Sheet in Flutter

How to Change / Update the State inside Bottom Sheet in Flutter

Bottom Sheets are one of the commonly used things in a mobile application. We can use them for different types of requirements. If we want to display some information to the user such as more details about something, then it can be a good place.

If we want to keep some settings inside the Bottom Sheet such as a check box, then handling the state of this check box can be tricky.

example:

bool toggleIcon = true;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Center(
          child: Column(
            children: [
              Icon(
                  toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
              ),
              ElevatedButton(onPressed: () {
                showModalBottomSheet(
                    context: context,
                    builder: ( BuildContext context ) {
                      return Container(
                        color: Colors.blue,
                        child: Column(
                          children: [
                            IconButton(onPressed:  () {
                              setState(() {
                                toggleIcon= !toggleIcon;
                              });
                            } ,
                                icon: Icon(
                                    toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
                                ) )
                          ],
                        ),
                      );
                    }
                );
              } , child: Text('Show Bottom Sheet'))
            ],
          ),
        ),
      ),
    ) ;
  }

In this example, we are showing bottom sheet which contains an icon button which changes the state of a property when we click on it. When we run this code and clicks on the icon button, then we can see that the icon which is inside the main body changes but not the icon which is inside the bottom sheet.

The reason is, when we click on the icon inside the bottom sheet, we are changing the state of the main widget but not the state of the bottom sheet. When we close the bottom bar and open it again, then we pass the updated context so we can find the updated icon.

Here, if you want, what you can do is, when the user clicks on the icon button inside the bottom sheet, after setting the state, you can immediately pop the bottom sheet by using Navigator.pop(context).

By Using StatefulBuilder

If you are concerned only about the state of the bottom sheet, and do not want to reflect any changes in the calling widget, you can use StatefulBuilder widget.

example:

replace the showModalBottomSheet from the previous example with this one

showModalBottomSheet(
                    context: context,
                    builder: ( BuildContext context ) {
                      return StatefulBuilder(
                        builder: (BuildContext context, StateSetter setState) {
                          return Container(
                            color: Colors.blue,
                            child: Column(
                              children: [
                                IconButton(onPressed:  () {
                                  setState(() {
                                    toggleIcon= !toggleIcon;
                                  });
                                } ,
                                    icon: Icon(
                                        toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
                                    ) )
                              ],
                            ),
                          );
                        } ,
                      );
                    }
                )

With this code, we are giving the bottom sheet, its own state. When you run the code with this example, now when you click on the icon button inside bottom sheet, you can find that the icon toggles inside the bottom sheet, but the one inside the body stays same.

Bottom Sheet as Stateful Widget

In-order to change the state inside the bottom sheet as well as the widget from which it is called, we can make a stateful widget and use it as a bottom sheet. We also need to pass a callback function to this widget which triggers setState in the parent widget.

example:

import 'package:flutter/material.dart';
class BottomSheetState extends StatefulWidget {
  @override
  _BottomSheetStateState createState() => _BottomSheetStateState();
}

class _BottomSheetStateState extends State<BottomSheetState> {
  bool toggleIcon = true;
  toggleIconState(bool value ) {
    setState(() {
      toggleIcon = value;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Center(
          child: Column(
            children: [
              Icon(
                  toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
              ),
              ElevatedButton(onPressed: () {
                showModalBottomSheet(
                    context: context,
                    builder: ( BuildContext context ) {
                      return StatefulBottomSheet(toggleIcon: toggleIcon, valueChanged: toggleIconState,);
                    }
                );
              } , child: Text('Show Bottom Sheet'))
            ],
          ),
        ),
      ),
    ) ;
  }
}

class StatefulBottomSheet extends StatefulWidget {
  final bool toggleIcon;
  final ValueChanged<bool> valueChanged;
  StatefulBottomSheet( {Key? key, required this.toggleIcon, required this.valueChanged } );

  @override
  _StatefulBottomSheetState createState() => _StatefulBottomSheetState();
}

class _StatefulBottomSheetState extends State<StatefulBottomSheet> {
  late bool _toggleIcon;
  @override
  void initState() {
    _toggleIcon = widget.toggleIcon;
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return  Container(
      color: Colors.blue,
      child: Column(
        children: [
          IconButton(onPressed:  () {
            setState(() {
              _toggleIcon= !_toggleIcon;
            });
            widget.valueChanged(_toggleIcon);
          } ,
              icon: Icon(
                  _toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
              ) )
        ],
      ),
    );
  }
}

By using Provider

Another way to achieve this functionality is by using Provider package. We can now create a provider and move all the properties and logic to it and add it to the main.dart file.

import 'package:flutter/material.dart';

class DataProvider extends ChangeNotifier {
  bool toggleIcon = true;

  toggleIconState() {
    toggleIcon = !toggleIcon;
    notifyListeners();
  }
}

We can now use this provider to change the state inside the widget as well as in the bottom sheet.

@override
  Widget build(BuildContext context) {
    DataProvider dataProvider = Provider.of<DataProvider>(context);
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Center(
          child: Column(
            children: [
              Icon(
                  dataProvider.toggleIcon ? Icons.check_box : Icons.check_box_outline_blank
              ),
              ElevatedButton(onPressed: () {
                showModalBottomSheet(
                    context: context,
                    builder: ( BuildContext context ) {
                      return Container(
                        color: Colors.blue,
                        child: Column(
                          children: [
                            IconButton(onPressed:  () {
                              Provider.of<DataProvider>(context, listen: false).toggleIconState();
                            } ,
                                icon: Icon(
                                    Provider.of<DataProvider>(context,).toggleIcon ? Icons.check_box :
                                    Icons.check_box_outline_blank
                                ) )
                          ],
                        ),
                      );
                    }
                );
              } , child: Text('Show Bottom Sheet'))
            ],
          ),
        ),
      ),
    ) ;
  }

Make sure that you have added the Provider dependency in the pubspec file.

Leave A Comment

Your email address will not be published. Required fields are marked *