如何从有状态小部件访问小部件状态 class Flutter

How to access a widgets state from a stateful widget class Flutter

抱歉,如果这个问题已经在其他地方得到回答,但我是 Flutter 的新手。我的小部件中有一个 toString 方法需要访问小部件的状态以输出字符串。小部件是一张包含文本字段和其他与文本相关的操作的卡片。要存储有关用户在卡中输入的内容的信息,我需要将所有数据放入一个字符串中,该字符串为 toString returns.

class TextCard extends StatefulWidget {
  _TextCardState cardState = _TextCardState();
  TextCard({String text = ""}) {
    cardState.textController.text = text;

  }
  @override
  _TextCardState createState() => cardState = new _TextCardState();

  String toString({DiagnosticLevel minLevel = DiagnosticLevel.debug}) {
    return delimiter2 +
        "TextCard" +delimiter3 +
        cardState.getText() +
        delimiter3 +
        (cardState.center.toString()) +
        delimiter3 +
        cardState.bold.toString() +
        delimiter3 +
        cardState.italic.toString() +
        delimiter3 +
        cardState.size.toString() +

        delimiter2;
  }
}

小部件还接受一个字符串值来设置以下状态的文本字段的初始值

class _TextCardState extends State<TextCard> {
  double size = 18;
  bool bold = false;
  bool italic = false;
  bool center = false;

  var textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Container(
        height: _cardSizeY,
        width: _cardSizeX,
        child: Card(
            elevation: _elevation,
            child: Center(
                child: Column(children: [
              ListTile(leading: Icon(Icons.text_fields)),
              ButtonBar(children: [
                IconButton(
                  icon: Icon(Icons.format_bold),
                  onPressed: () {
                    updateText(size, !bold, italic, center);
                  },
                ),
                IconButton(
                  icon: Icon(Icons.format_italic),
                  onPressed: () {
                    updateText(size, bold, !italic, center);
                  },
                ),
                Slider(
                    value: size,
                    max: 80,
                    min: 1,
                    onChanged: (size) {
                      updateText(size, bold, italic, center);
                    })
              ]),
              TextField(
                  maxLines: null,
                  style: TextStyle(
                      fontWeight: (bold) ? FontWeight.bold : FontWeight.normal,
                      fontStyle: (italic) ? FontStyle.italic : FontStyle.normal,
                      fontSize: size),
                  textAlign: (center) ? TextAlign.center : TextAlign.start,
                  controller: textController,
                  decoration: InputDecoration(
                      border: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.grey),
                          borderRadius: BorderRadius.all(Radius.circular(10)))))
            ]))));
  }

  void updateText(double size, bool bold, bool italic, bool center) {
    setState(() {
      this.size = size;
      this.bold = bold;
      this.italic = italic;
      this.center = center;
    });
  }

  String getText() {
    return textController.value.text;
  }
}

当我 运行 这段代码出现错误时,创建状态函数返回了一个旧的无效状态实例。 我研究过将文本控制器放入 _TextCardState() class,但我无法更改 TextField 的初始值。

所以我明白你在这里想做什么,但是有更好的方法可以从 class.

之外访问文本字段的值

我建议使用一种状态管理解决方案,而不是从外部访问您的 toString 方法,它依赖于私有状态 class 的值,这将使这种方式更容易和更清晰。您还可以更轻松地访问所需的所有变量。

你在这里做的不是你应该做的事情,这就是你得到这些状态错误的原因。

_TextCardState cardState = _TextCardState();

这是一种使用 GetX 的方法。

您的所有数据都将保存在下面的 GetX 控制器 class 中,并将用于您现在的无状态 TextCard 小部件。

class Controller extends GetxController {
  var textController = TextEditingController();
  String textfieldString = '';
  double size = 18;
  bool bold = false;
  bool italic = false;
  bool center = false;

  @override
  void onInit() {
    super.onInit();
    // updates the value of textfieldString anytime the user types
    textController.addListener(() {
      textfieldString = textController.text;
      debugPrint(textController.text);
    });
  }

  // this method lives in this class and is accessible from anywhere. The
// only thing not clear is what delimier2 is and where it comes from
// toString is not a good name because that is an overridden method that lives 
// in most Dart classes

   String buildString({DiagnosticLevel minLevel = DiagnosticLevel.debug}) {
    return delimiter2 +
        "TextCard" +delimiter3 +
        textfieldString +
        delimiter3 +
        (center.toString()) +
        delimiter3 +
        bold.toString() +
        delimiter3 +
        italic.toString() +
        delimiter3 +
        size.toString() +

        delimiter2;
  }

// single responsibility methods as opposed to firing one big function 
// multiple times when its only affecting one variable

  void toggleBold() {
    bold = !bold;
    update();
  }

  void toggleItalic() {
    italic = !italic;
    update();
  }

  void toggleCenter() {
    center = !center;
    update();
  }

  void updateSize(double sliderValue) {
    size = sliderValue;
    update();
  }
}

将此放在您的主程序中 运行 您的应用程序之前。只要在您尝试访问控制器之前,就可以在任何地方完成。

  Get.put(Controller()); 

这是您的 TextCard 小部件

class TextCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller =
        Get.find<Controller>(); // finding the initalized controller
    return Container(
      height: _cardSizeY,
      width: _cardSizeX,
      child: Card(
        elevation: 20,
        child: Center(
          child: Column(
            children: [
              ListTile(leading: Icon(Icons.text_fields)),
              ButtonBar(children: [
                IconButton(
                  icon: Icon(Icons.format_bold),
                  onPressed: () {
                    controller.toggleBold();
                  },
                ),
                IconButton(
                  icon: Icon(Icons.format_italic),
                  onPressed: () {
                    controller.toggleItalic(); // accessing method via controller
                  },
                ),
                // GetBuilder rebuilds children when value of controller variable changes
                GetBuilder<Controller>(
                  builder: (_) {
                    return Slider(
                        value: controller
                            .size, // accessing size in other class via controller
                        max: 80,
                        min: 1,
                        onChanged: (value) {
                          controller.updateSize(value); 
                        });
                  },
                )
              ]),
              GetBuilder<Controller>(
                builder: (_) {
                  return TextField(
                    maxLines: null,
                    style: TextStyle(
                        fontWeight: (controller.bold)
                            ? FontWeight.bold
                            : FontWeight.normal,
                        fontStyle: (controller.italic)
                            ? FontStyle.italic
                            : FontStyle.normal,
                        fontSize: controller.size),
                    textAlign: (controller.center)
                        ? TextAlign.center
                        : TextAlign.start,
                    controller: controller.textController,
                    decoration: InputDecoration(
                      border: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.grey),
                        borderRadius: BorderRadius.all(
                          Radius.circular(10),
                        ),
                      ),
                    ),
                  );
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

因此,无论您在应用程序的哪个位置需要该功能,都可以找到控制器并获取您的值。

final controller = Get.find<Controller>():
final newString = controller.buildString();

这会更容易并且使用更少的内存,因为 TextCard 现在是无状态的。