ritz
ritz

Reputation: 215

Obtain variable value from a different widget

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}'),
    );
  }
}

Upvotes: 1

Views: 143

Answers (1)

Christopher Moore
Christopher Moore

Reputation: 17113

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}'),
    );
  }
}

Upvotes: 2

Related Questions