[Solved] Changing the state Widget of one through another Widget

Question

Asked by Cassiano J on December 02, 2021 (source).

MyHomePageState:

Widget build(BuildContext context) {
        double screenWidth = MediaQuery.of(context).size.width;
        return Scaffold(
            backgroundColor: bgColor,
            body: ListView(
              children: <Widget>[
                Stack(
                  alignment: Alignment.topCenter,
    
                  children: <Widget>[
                    mainWidget(),
    
                  ],
                ),
                connectedStatusText(),
              ],
            ));
      }

I'm trying to change the status of connectedStatusText() from mainWidget()!

My connectedStatus:

class connectedStatusText extends StatefulWidget
{
  State<connectedStatusText> createState() {
    return connectedStatus();
  }
}

class connectedStatus extends State<connectedStatusText> {
  String status = "IDLE";
  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.center,
          child: RichText(
            textAlign: TextAlign.center,
            text: TextSpan(text: 'Status:', style: connectedStyle, children: [
              TextSpan(text: status, style: disconnectedRed)
            ]),
          ),
    );
  }

}

I want to change the $status text to "connected" through ontap of mainWidget().

mainWidget:

....
class mainWidget extends StatefulWidget
{
  MyED createState() => new MyED();
}


class MyED extends State<mainWidget> {
 child: new GestureDetector(
          onTap: () => setState(() {
                          //change here
                      }

tried to set a global variable to connectedStatus:

GlobalKey<connectedStatus> key = GlobalKey<connectedStatus>();

and change by ontap...

 child: new GestureDetector(
          onTap: () => setState(() {
                          //change here
                           key.currentState.status = "CONNECTED";
                      }
          )
}

but it does not work! Any help for me to change this text through another place?

Answer

Question answered by Tejaswini D (source).

Please refer to below example code to update state using ValueNotifier and ValueListenableBuilder.

ValueNotifer & ValueListenableBuilder can be used to hold value and update widget by notifying its listeners and reducing number of times widget tree getting rebuilt.

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Screen2(),
    );
  }
}

class Screen2 extends StatefulWidget {
  final String userId; // receives the value

  const Screen2({Key key, this.userId}) : super(key: key);

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

class _Screen2State extends State<Screen2> {
  final ValueNotifier<bool> updateStatus = ValueNotifier(false);
  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;
    return Scaffold(
      backgroundColor: Colors.blue,
      body: ListView(
        children: <Widget>[
          Stack(
            alignment: Alignment.topCenter,
            children: <Widget>[
              mainWidget(
                updateStatus: updateStatus,
              ),
            ],
          ),
          connectedStatusText(
            updateStatus: updateStatus,
          ),
        ],
      ),
    ); // uses the value
  }
}

class connectedStatusText extends StatefulWidget {
  final ValueNotifier<bool> updateStatus;

  connectedStatusText({
    Key key,
    this.updateStatus,
  }) : super(key: key);

  State<connectedStatusText> createState() {
    return connectedStatus();
  }
}

class connectedStatus extends State<connectedStatusText> {
  String status = "IDLE";

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.center,
      child: /* 
              In order update widget we can use ValueListenableBuilder which updates the particular widget when the value changes (ValueNotifier value)
            */
          ValueListenableBuilder(
              valueListenable: widget.updateStatus,
              builder: (context, snapshot, child) {
                return RichText(
                  textAlign: TextAlign.center,
                  text: TextSpan(text: 'Status:', children: [
                    TextSpan(
                      text: (widget.updateStatus.value == true)
                          ? "Active"
                          : status,
                    )
                  ]),
                );
              }),
    );
  }
}

class mainWidget extends StatefulWidget {
  final String userId; // receives the value
  final ValueNotifier<bool> updateStatus;

  mainWidget({
    Key key,
    this.userId,
    this.updateStatus,
  }) : super(key: key);

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

class _mainWidgetState extends State<mainWidget> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onTap: () {
          widget.updateStatus.value = !widget.updateStatus.value;
        },
        child: ValueListenableBuilder(
            valueListenable: widget.updateStatus,
            builder: (context, snapshot, child) {
              return Text(snapshot.toString());
            }));

    // uses the value
  }
}


DART FLUTTER
SHARE: