1

What I want is when I click the switch button, the text in the Option1Content widget should change to true or false (depending upon the current value of the switch). The value is correct when you click the tile, select a different option from the drawer, and then come back to option 1, you will have the correct value. My requirement is when I press the switch tile the value of Option1Content should change instantly. For functionality reference: https://dartpad.dev/c9cabc35a0bda57758b1d1cf07f8a823. Any help would be greatly appreciated. Thank you.

import 'package:flutter/material.dart';


void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget{
  MyWidgetState createState()=> MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
  bool status;
  Widget myBody;
  GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  
   void closeDrawer() {
    if (_scaffoldKey.currentState.isDrawerOpen) {
      _scaffoldKey.currentState.openEndDrawer();
    }
  }
  
  @override
  void initState(){
    super.initState();
    status = false;
    myBody = Option1Content(status:status);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key:_scaffoldKey,
    appBar:AppBar(
      iconTheme: IconThemeData(color: Colors.black),
      elevation:0,
      backgroundColor:Colors.transparent,
    actions:[
      Switch(
        inactiveThumbColor: Colors.black,
        activeColor: Colors.green,
        value:status,
        onChanged:(value){
          setState((){
            status=value;
          });
        })
    ]
    ),
      drawer: Drawer(
        child:Center(child:ListView(children:[
          DrawerHeader(
                      child: Column(
                        children: <Widget>[
                          CircleAvatar(
                            radius: 50,
                            backgroundColor: Colors.grey,
                          ),
                          Padding(
                            padding: const EdgeInsets.only(
                                left: 8.0, right: 8.0, top: 12.0),
                            child: Text(
                              'Account',
                              style: TextStyle(
                                fontWeight: FontWeight.bold,
                              ),
                              textScaleFactor: 1.3,
                            ),
                          ),
                        ],
                      ),
                    ),
          ListTile(title:Center(child:Text('Option 1')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Option1Content(status:status);
            });
          }),
          ListTile(title:Center(child:Text('Option 2')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Center(child:Text('Option 2 Content'));
            });
          }),
          ListTile(title:Center(child:Text('Option 3')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Center(child:Text('Option 3 Content'));
            });
          }),
        ]))
      ),
      body: myBody
    );
  }
}



class Option1Content extends StatefulWidget {
  final bool status;
  Option1Content({@required this.status});

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

class _Option1ContentState extends State<Option1Content> {

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('${widget.status}'),
    );
  }
}

1 Answer 1

2

The issue is that simply changing the value of status doesn't update what is actually in myBody, which is what's shown. Even when changing status with setState, myBody still contains your widget with the old value of status. This is why when you go to another myBody and come back, it's updated, because myBody now has the new widget with the updated status value.

To solve this you need to have a method of updating what's contained in myBody, because that's the only part that's being built. Doing the following is the simplest change.

Just change

setState((){
  status = value;
});

to

setState((){
  status = value;
  myBody = Option1Content(status:status);
});

and the full code:

import 'package:flutter/material.dart';


void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget{
  MyWidgetState createState()=> MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
  bool status;
  Widget myBody;
  GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  
   void closeDrawer() {
    if (_scaffoldKey.currentState.isDrawerOpen) {
      _scaffoldKey.currentState.openEndDrawer();
    }
  }
  
  @override
  void initState(){
    super.initState();
    status = false;
    myBody = Option1Content(status:status);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key:_scaffoldKey,
    appBar:AppBar(
      iconTheme: IconThemeData(color: Colors.black),
      elevation:0,
      backgroundColor:Colors.transparent,
    actions:[
      Switch(
        inactiveThumbColor: Colors.black,
        activeColor: Colors.green,
        value:status,
        onChanged:(value){
          setState((){
            status = value;
            myBody = Option1Content(status:status);
          });
        })
    ]
    ),
      drawer: Drawer(
        child:Center(child:ListView(children:[
          DrawerHeader(
                      child: Column(
                        children: <Widget>[
                          CircleAvatar(
                            radius: 50,
                            backgroundColor: Colors.grey,
                          ),
                          Padding(
                            padding: const EdgeInsets.only(
                                left: 8.0, right: 8.0, top: 12.0),
                            child: Text(
                              'Account',
                              style: TextStyle(
                                fontWeight: FontWeight.bold,
                              ),
                              textScaleFactor: 1.3,
                            ),
                          ),
                        ],
                      ),
                    ),
          ListTile(title:Center(child:Text('Option 1')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Option1Content(status:status);
            });
          }),
          ListTile(title:Center(child:Text('Option 2')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Center(child:Text('Option 2 Content'));
            });
          }),
          ListTile(title:Center(child:Text('Option 3')),onTap:(){
            closeDrawer();
            setState((){
              myBody = Center(child:Text('Option 3 Content'));
            });
          }),
        ]))
      ),
      body: myBody
    );
  }
}



class Option1Content extends StatefulWidget {
  final bool status;
  Option1Content({@required this.status});

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

class _Option1ContentState extends State<Option1Content> {

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('${widget.status}'),
    );
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot!. Any suggestions to handle this kind of scenario? I click one of the drawer element and the body is rebuilt?
@ritz This seems like a separate question. Please create a new question so you can provide more detail into your problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.