如何在不存在于同一文件中的两个小部件之间传递文本值

时间:2020-10-17 13:10:37

标签: flutter dart

我有以下小部件,其中每个小部件都存在于各自的文件中。

(每个文件中还有很多其他事情。我对其进行了压缩,以使其最小化,以便仅查看此查询所需的内容。)

我希望在一个窗口小部件中捕获传递到TextFormField中的值,并在另一个窗口小部件中打印出这些值。

没有可视状态的变化,因此尝试不通过Provider存储这些值,我认为对于此用例来说这很愚蠢。

因此,查询是关于如何向下传递每个小部件实例在TextEditingController中捕获的值并将其向下传递给另一个小部件?

重申以下三个类,它们存在于自己的Dart文件中。

最初,我对这3种产品都坚持使用无状态小部件,但从我的阅读中可以得知,建议用户使用涉及TextEditingController的有状态小部件。

因此MyField小部件是有状态的。

MyField窗口小部件-这是根据输入的内容将值存储到控制器的地方。

class MyField extends StatefulWidget {

  final String title;
  final TextEditingController controller;

  const MyField({this.controller, this.title});

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

class _MyFieldState extends State<MyField> {

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: widget.controller,
    );
  }
}

MyForm窗口小部件-它接受上述窗口小部件的2个实例,每个实例都有其自己的控制器。

此小部件有助于将文本值向下传递到MyButton小部件。

class MyForm extends StatelessWidget {
  final formKey = GlobalKey<FormState>();

  final nameController = TextEditingController();
  final passController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Stack(
        children: [
          MyField(
            title: 'name',
            controller: nameController,
          ),
          MyField(
            title: 'pass',
            controller: passController,
          ),
          MyButton(
              name: nameController.text,
              pass: passController.text,
              formKey: formKey)
        ],
      ),
    );
  }
}

MyButton窗口小部件-此窗口小部件捕获这些文本值并尝试打印出这些值,并且当前显示为空。

class MyButton extends StatelessWidget {

  final formKey;
  final String name;
  final String pass;

  const MyButton({Key key, this.formKey, this.name, this.pass}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        // I want to be able to retrieve the text via the controllers for the 2 text fields.
        // currently these values are empty which is the issue.
        print('name: $name pass: $pass');
      },
    );
  }
}

4 个答案:

答案 0 :(得分:0)

这是我的尝试。

  • 需要在MyForm类中从“堆栈”更改为“列”。
  • 使用“ formKey”从TextFormField获取值 (尽管我使用了一个formkey,但是我希望从'MyForm'之外控制值,而不是使用'formkey'获取值)
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _buildBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  Widget _buildBody() {
    return MyForm();
  }
}

class MyButton extends StatelessWidget {
  final formKey;
  final String label;

  const MyButton({Key key, this.formKey, this.label}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        // I want to be able to retrieve the text via the controllers for the 2 text fields.
        // currently these values are empty which is the issue.
        print(
            'name: ${formKey.currentWidget.child.children[0].controller.text} ');
        print(
            'pass: ${formKey.currentWidget.child.children[1].controller.text} ');
      },
      child: Text(label),
    );
  }
}

class MyForm extends StatelessWidget {
  final formKey = GlobalKey<FormState>();

  final nameController = TextEditingController();
  final passController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        children: [
          MyField(
            title: 'name',
            controller: nameController,
          ),
          MyField(
            title: 'pass',
            controller: passController,
          ),
          MyButton(label: 'Button', formKey: formKey)
        ],
      ),
    );
  }
}

class MyField extends StatefulWidget {
  final String title;
  final TextEditingController controller;

  const MyField({this.controller, this.title});

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

class _MyFieldState extends State<MyField> {
  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: widget.controller,
    );
  }
}

答案 1 :(得分:0)

好吧,如果您不使用用户输入的文本来更新MyButton小部件的UI状态,您甚至不需要它,您只需访问MyForm小部件中的控制器文本即可。

class MyForm extends StatelessWidget {
  final formKey = GlobalKey<FormState>();

  final nameController = TextEditingController();
  final passController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        children: [
          MyField(
            title: 'name',
            controller: nameController,
          ),
          MyField(
            title: 'pass',
            controller: passController,
          ),
          RaisedButton(
            onPressed() {
               print("${nameController.text}");
               print("${passController.text}");
             }
          ),
        ],
      ),
    );
  }
}

但是,如果您想在用户键入文本时动态更新MyButton小部件,则MyForm小部件必须为Statefull,并且必须在每个用户类型事件中进行重建。 / p>

 //NOTE: Assuming `MyForm` is a Statefull widget
  final nameController = TextEditingController();
  final passController = TextEditingController();

  @override
  void initState() {
     // listening the textfield.
     nameController.addListener(_controllerListener);
     passController.addListener(_controllerListener);
     super.initState();
  }

  void _controllerListener(){
     if(mounted)
       setState((){});
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Stack(
        children: [
          MyField(
            title: 'name',
            controller: nameController,
          ),
          MyField(
            title: 'pass',
            controller: passController,
          ),
          MyButton(
              name: nameController.text,
              pass: passController.text,
              onPressed: () {
                 print("${nameController.text} - ${passController.text}");
              })
        ],
      ),
    );
  }
}

class MyButton extends StatelessWidget {
  final String name;
  final String pass;
  final VoidCallback onPressed;

  const MyButton({Key key, this.onPressed, this.name, this.pass}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: this.onPressed,

      // updating UI on type event.
      child: Text('$name and $pass'),
    );
  }
}

答案 2 :(得分:0)

请将MyForm类更改为以下类... 这个怎么运作 ? 在TextFormField上进行每次更改后,您的Button应该重新构建,因此我使用了Stream构建器和Stream

class MyForm extends StatelessWidget {
  final formKey = GlobalKey<FormState>();

  final nameController = TextEditingController();
  final passController = TextEditingController();

  StreamController<int> sc = StreamController<int>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      onChanged: () {
        sc.add(1);
      },
      child: Column(
        children: [
          MyField(
            title: 'name',
            controller: nameController,
          ),
          MyField(
            title: 'pass',
            controller: passController,
          ),
          StreamBuilder<int>(
            stream: sc.stream,
            builder: (context, snapshot) {
              return MyButton(
                  name: nameController.text,
                  pass: passController.text,
                  formKey: formKey);
            }
          )
        ],
      ),
    );
  }
}

答案 3 :(得分:0)

您可以将值存储在目标文件中,并从项目中的任何其他文件中获取或编辑其值。例如,在名为user.dart的文件中:

ID | column 1 | column 2
1  | peter    | blue
2  | mark     | red
1  | peter    | blue

然后在其他任何位置导入文件并根据需要设置或获取其值:

class user {
  static String name;
  static String pass;
}

如果您的问题是您想在单击按钮之前显示文本,那么我认为您可以使小部件成为有状态的,然后可以在“文本”字段中使用change事件:

user.name = nameController.text
user.pass = passController.text

print('name: ' + user.name + 'pass: ' + user.pass);