Flutter showModalBottomSheet not changing state need to reopen it to see changes

Viewed 942

I am showing showModalBottomSheet issue is its not changing the state I need t close the showModalBottomSheet and open it again to see the changes. Here is my code

List sort = [
  {'CatID': 0, 'Name': 'Trending'},
  {'CatID': 1, 'Name': 'Newest'},
  {'CatID': 2, 'Name': 'Lowset Price'},
  {'CatID': 3, 'Name': 'Highest Price'},
];

class BrowserCategoryPage2 extends StatefulWidget {
  final subCategory;
  const BrowserCategoryPage2({Key key, @required this.subCategory})
      : super(key: key);

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

class _BrowserCategoryPage2State extends State<BrowserCategoryPage2> {
  var items = {'Items': []};
  int dateindex;
  bool showNotAvail = false;
  @override
  void initState() {
    super.initState();

    print('browse subcategory');
    print(widget.subCategory);

    widget.subCategory.forEach((subcategory) {
      items['Items'].addAll(subcategory['Items']);
    });
    print(items);
    print('sada');
  }

  int currentindex = 0;
  int sortindex = 0;

  @override
  Widget build(BuildContext context) {
    double Height = MediaQuery.of(context).size.height;
    double Width = MediaQuery.of(context).size.width;



    return Scaffold(
      body: Container(
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              SideInAnimation(
                2,
                child: Align(
                  alignment: Alignment.topLeft,
                  child: Padding(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 18.0, vertical: 18),
                    child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(
                            'Products',
                            style: Theme.of(context).textTheme.headline3,
                          ).tr(),
                          IconButton(
                            icon: Icon(
                              FlutterIcons.filter_fea,
                              color: Theme.of(context).primaryColor,
                            ),
                            onPressed: () {
                              OpenFilter(context);
                            },
                          ),
                        ]),
                  ),
                ),
              ),
              SizedBox(height: 10.0),
            ],
          ),
        ),
      ),
    );
  }
  
  OpenFilter(BuildContext context){
    return showModalBottomSheet<void>(
        context: context,
        builder: (BuildContext context) {
          double Height = MediaQuery.of(context).size.height;
          double Width = MediaQuery.of(context).size.width;


          final SortWidget = <Widget>[]; // Here we defined a list of widget!

          for (int i = 0; i < sort.length; i++) {
            SortWidget.add(
              GestureDetector(
                onTap: () {
                  setState(() {
                    // set current index!
                    sortindex = i;
                    print(sortindex);
                  });
                },
                child: Container(
                  height: Height * 0.04,
                  width: Width * 0.2,
                  decoration: BoxDecoration(
                      color: sortindex == i ? Color(0xff04385f) : Colors.white,
                      border: Border.all(
                          color:
                          sortindex == i ? Color(0xff04385f) : Colors.grey[500]),
                      borderRadius: BorderRadius.all(Radius.circular(10))),
                  child: Center(
                      child: Text(
                        sort[i]['Name'],
                        textAlign: TextAlign.center,
                        style: TextStyle(
                            fontSize: 9,
                            color: sortindex == i ? Colors.white : Colors.grey[500],
                            fontFamily: 'UbuntuRegular'),
                      )),
                ),
              ),
            );
          }

          return Container(
            decoration: BoxDecoration(
                borderRadius: new BorderRadius.only(
                    topLeft:
                    const Radius.circular(10.0),
                    topRight:
                    const Radius.circular(10.0))),
            child: new Column(
              children: [
                Container(
                  width: double.infinity,
                  height: Height * 0.055,
                  decoration: BoxDecoration(
                      color: Color(0xfff7f7f7)),
                  child: Center(
                    child: RichText(
                      text: new TextSpan(
                        style: new TextStyle(
                          fontSize: 14.0,
                          color: Colors.black,
                        ),
                        children: <TextSpan>[
                          new TextSpan(
                              text: 'Sort & ',
                              style: new TextStyle(
                                  fontSize: 18,
                                  fontFamily:
                                  'UbuntuBold')),
                          new TextSpan(
                              text: 'Filter',
                              style: TextStyle(
                                fontSize: 18,
                                fontFamily:
                                'UbuntuMedium',
                              )),
                        ],
                      ),
                    ),
                  ),
                ),
                SizedBox(
                  height: Height * 0.01,
                ),
                Padding(
                  padding: const EdgeInsets.only(
                      left: 13, bottom: 13),
                  child: Align(
                    alignment: Alignment.centerLeft,
                    child: RichText(
                      text: new TextSpan(
                        // Note: Styles for TextSpans must be explicitly defined.
                        // Child text spans will inherit styles from parent
                        style: new TextStyle(
                          fontSize: 14.0,
                          color: Colors.black,
                        ),
                        children: <TextSpan>[
                          new TextSpan(
                              text: 'Sort ',
                              style: new TextStyle(
                                  fontSize: 16,
                                  fontFamily:
                                  'UbuntuBold')),
                          new TextSpan(
                              text: 'By',
                              style: TextStyle(
                                fontSize: 16,
                                fontFamily:
                                'UbuntuMedium',
                              )),
                        ],
                      ),
                    ),
                  ),
                ),
                Row(
                  mainAxisAlignment:
                  MainAxisAlignment.spaceAround,
                  children: SortWidget,
                ),
                Padding(
                  padding: const EdgeInsets.only(
                      left: 13, right: 13, top: 13),
                  child: Divider(
                    color: Colors.grey,
                    thickness: 1,
                  ),
                ),
                SizedBox(
                  height: Height * 0.01,
                ),

                Padding(
                  padding: const EdgeInsets.only(
                      left: 10, right: 10, top: 20),
                  child: Row(
                    mainAxisAlignment:
                    MainAxisAlignment
                        .spaceBetween,
                    children: [
                      Container(
                        height: Height * 0.06,
                        width: Width * 0.57,
                        decoration: BoxDecoration(
                          color: Color(0xff04385f),
                          borderRadius:
                          BorderRadius.only(
                              topLeft:
                              Radius.circular(
                                  12),
                              topRight:
                              Radius.circular(
                                  12),
                              bottomLeft:
                              Radius.circular(
                                  12),
                              bottomRight:
                              Radius.circular(
                                  12)),
                        ),
                        child: Center(
                            child: Text(
                              'Apply Filters',
                              style: TextStyle(
                                  fontSize: 15,
                                  fontWeight:
                                  FontWeight.bold,
                                  fontFamily:
                                  'UbuntuRegular',
                                  color: Colors.white),
                            )),
                      ),
                      Container(
                        height: Height * 0.06,
                        width: Width * 0.3,
                        decoration: BoxDecoration(
                          border: Border.all(
                              color: Colors.grey),
                          color: Colors.white,
                          borderRadius:
                          BorderRadius.only(
                              topLeft:
                              Radius.circular(
                                  12),
                              topRight:
                              Radius.circular(
                                  12),
                              bottomLeft:
                              Radius.circular(
                                  12),
                              bottomRight:
                              Radius.circular(
                                  12)),
                        ),
                        child: Center(
                            child: Text(
                              'Reset',
                              style: TextStyle(
                                  fontSize: 15,
                                  fontWeight:
                                  FontWeight.bold,
                                  fontFamily:
                                  'UbuntuRegular',
                                  color:
                                  Color(0xff04385f)),
                            )),
                      ),
                    ],
                  ),
                )
              ],
            ),
          );
        });
  }
}

You can see I simply change the color of the container on click. It's changing the index of sort index but issue is it's not changing the state. Mean if I close and open the bottom sheet then I can see the changes.

2 Answers

If flutter BottomSheet works as a widget, so bottomSheet has its own state which does not refresh the data when you call setState({}) of parent Class.

For that you need to use StatefulBuilder for refresh the content of bottomSheet like :

await showModalBottomSheet(
        context: context,
        builder: (BuildContext bc) {
          return StatefulBuilder(builder: (BuildContext context, StateSetter state) {
            return Container();
          });
        });

Please replace your method with the following solution it will work properly:

OpenFilter(BuildContext context) {
    return showModalBottomSheet<void>(
        context: context,
        builder: (BuildContext context) {
          return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
            double Height = MediaQuery.of(context).size.height;
            double Width = MediaQuery.of(context).size.width;

            final SortWidget = <Widget>[]; // Here we defined a list of widget!

            for (int i = 0; i < sort.length; i++) {
              SortWidget.add(
                GestureDetector(
                  onTap: () {
                    setState(() {
                      // set current index!
                      sortindex = i;
                      print(sortindex);
                    });
                  },
                  child: Container(
                    height: Height * 0.04,
                    width: Width * 0.2,
                    decoration: BoxDecoration(
                        color: sortindex == i ? Color(0xff04385f) : Colors.white,
                        border: Border.all(color: sortindex == i ? Color(0xff04385f) : Colors.grey[500]),
                        borderRadius: BorderRadius.all(Radius.circular(10))),
                    child: Center(
                        child: Text(
                      sort[i]['Name'],
                      textAlign: TextAlign.center,
                      style: TextStyle(
                          fontSize: 9,
                          color: sortindex == i ? Colors.white : Colors.grey[500],
                          fontFamily: 'UbuntuRegular'),
                    )),
                  ),
                ),
              );
            }
            return Container(
              decoration: BoxDecoration(
                  borderRadius: new BorderRadius.only(
                      topLeft: const Radius.circular(10.0), topRight: const Radius.circular(10.0))),
              child: new Column(
                children: [
                  Container(
                    width: double.infinity,
                    height: Height * 0.055,
                    decoration: BoxDecoration(color: Color(0xfff7f7f7)),
                    child: Center(
                      child: RichText(
                        text: new TextSpan(
                          style: new TextStyle(
                            fontSize: 14.0,
                            color: Colors.black,
                          ),
                          children: <TextSpan>[
                            new TextSpan(text: 'Sort & ', style: new TextStyle(fontSize: 18, fontFamily: 'UbuntuBold')),
                            new TextSpan(
                                text: 'Filter',
                                style: TextStyle(
                                  fontSize: 18,
                                  fontFamily: 'UbuntuMedium',
                                )),
                          ],
                        ),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: Height * 0.01,
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 13, bottom: 13),
                    child: Align(
                      alignment: Alignment.centerLeft,
                      child: RichText(
                        text: new TextSpan(
                          // Note: Styles for TextSpans must be explicitly defined.
                          // Child text spans will inherit styles from parent
                          style: new TextStyle(
                            fontSize: 14.0,
                            color: Colors.black,
                          ),
                          children: <TextSpan>[
                            new TextSpan(text: 'Sort ', style: new TextStyle(fontSize: 16, fontFamily: 'UbuntuBold')),
                            new TextSpan(
                                text: 'By',
                                style: TextStyle(
                                  fontSize: 16,
                                  fontFamily: 'UbuntuMedium',
                                )),
                          ],
                        ),
                      ),
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    children: SortWidget,
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 13, right: 13, top: 13),
                    child: Divider(
                      color: Colors.grey,
                      thickness: 1,
                    ),
                  ),
                  SizedBox(
                    height: Height * 0.01,
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 10, right: 10, top: 20),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Container(
                          height: Height * 0.06,
                          width: Width * 0.57,
                          decoration: BoxDecoration(
                            color: Color(0xff04385f),
                            borderRadius: BorderRadius.only(
                                topLeft: Radius.circular(12),
                                topRight: Radius.circular(12),
                                bottomLeft: Radius.circular(12),
                                bottomRight: Radius.circular(12)),
                          ),
                          child: Center(
                              child: Text(
                            'Apply Filters',
                            style: TextStyle(
                                fontSize: 15,
                                fontWeight: FontWeight.bold,
                                fontFamily: 'UbuntuRegular',
                                color: Colors.white),
                          )),
                        ),
                        Container(
                          height: Height * 0.06,
                          width: Width * 0.3,
                          decoration: BoxDecoration(
                            border: Border.all(color: Colors.grey),
                            color: Colors.white,
                            borderRadius: BorderRadius.only(
                                topLeft: Radius.circular(12),
                                topRight: Radius.circular(12),
                                bottomLeft: Radius.circular(12),
                                bottomRight: Radius.circular(12)),
                          ),
                          child: Center(
                              child: Text(
                            'Reset',
                            style: TextStyle(
                                fontSize: 15,
                                fontWeight: FontWeight.bold,
                                fontFamily: 'UbuntuRegular',
                                color: Color(0xff04385f)),
                          )),
                        ),
                      ],
                    ),
                  )
                ],
              ),
            );
          });
        });
  }

Flutter is amazing at rebuilding its widgets as little as possible. So if there are any constant widgets/values, it won't rebuild them. This also applies to bottom sheets.

If you would like to have your bottom sheet update with hot restart you can create a stateful widget within your bottomsheet and then it will update.

Here is an example of such:

class MyBottomSheet extends StatefulWidget {
  const MyBottomSheet({
    Key key,
  }) : super(key: key);

  Future<T> show<T>(BuildContext context) {
    return showModalBottomSheet<T>(
      context: context,
      isDismissible: true,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (_) => return this,
    );
  }

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

class _MyBottomSheetState extends State<MyBottomSheet> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: 310,
    );
  }
}

and to access the bottom sheet you can call it via MyBottomSheet().show(context);

Related