将表单分解为多个小部件并与这些小部件进行交互

时间:2019-07-08 18:08:06

标签: flutter

我有一个表单,为了决定代码的可重用性,我决定将其分成多个小部件。我遇到的问题我不知道如何与每个组件进行交互。例如,如果主窗体声明了一个变量,我如何在存储在不同dart文件中的自定义文本字段小部件中访问该变量。

下面是我的代码

表单dart文件(main.dart)

import 'package:flutter/material.dart';
import 'package:finsec/widget/row_text_input.dart';
import 'package:finsec/widget/text_form_field.dart';
import 'package:finsec/widget/save_button.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/dimens.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/column_text_input.dart';

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: 'Simple Interest Calculator App',
    home: ThirdFragment(),
    theme: ThemeData(
        brightness: Brightness.dark,
        primaryColor: Colors.indigo,
        accentColor: Colors.indigoAccent),
  ));
}

class ThirdFragment extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ThirdFragmentState();
  }
}

class _ThirdFragmentState extends State<ThirdFragment> {

  var _formKey = GlobalKey<FormState>();
  var _currentItemSelected = '';
  bool isError = false;
  bool isButtonPressed = false;

  @override
  void initState() {
    super.initState();
  }



  TextEditingController amountController = TextEditingController();
  TextEditingController frequencyController = TextEditingController();


  @override
  Widget build(BuildContext context) {
    TextStyle textStyle = Theme.of(context).textTheme.title;

    return Scaffold(
      appBar: AppBar(
        title: Text('Simple Interest Calculator'),
      ),
      body: Form(
        key: _formKey,      
        child: SingleChildScrollView(
          child: Column (children: [
            Padding(
              padding: EdgeInsets.only(top: 10.0, bottom: 5.0, left: 15.0, right: 15.0),
              child: CustomTextField(textInputType:TextInputType.number,
                textController: amountController,
                errorMessage:'Enter Income Amount',
                labelText:'Income Amount for testing'),
            ),
            RowTextInput(inputName: 'Frequency:',
              textInputType: TextInputType.number,
              textController: frequencyController,
              errorMessage: 'Choose Income Frequency',
              labelText: 'Income Amount for testing'
            ),
            RowTextInput(inputName: 'Date Paid:',
                textInputType: TextInputType.number,
                textController: datePaidController,
                errorMessage: 'Pick Income Payment Date',
                labelText: 'Income Amount for testing'
            ),

            SizedBox(height: 20),


          Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                MaterialButton(
                  height: margin_40dp,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
                  minWidth: (MediaQuery.of(context).size.width * .9) / 2,
                  color: Theme.of(context).primaryColor,
                  textColor: white,
                  child: new Text(save),
                  onPressed: () => {
                  setState(() {
                  if (_formKey.currentState.validate()) {
                    // amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
                  //this.displayResult = _calculateTotalReturns();
                  }
                  })
                  },
                  splashColor: blueGrey,
                ),
                MaterialButton(
                  height: margin_40dp,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
                  minWidth: (MediaQuery.of(context).size.width * .9) / 2,
                  color: Theme.of(context).primaryColor,
                  textColor: white,
                  child: new Text(save_and_continue),
                  onPressed: () => {},
                  splashColor: blueGrey,
                )
              ])
          ]
          ),
      ),
}

RowTextInput是另一个包含此代码的dart文件。 RowTextInput.dart

import 'package:flutter/material.dart';
import 'package:finsec/utils/hex_color.dart';

class CustomTextField extends StatelessWidget {
  CustomTextField({
    this.textInputType,
    this.textController ,
    this.errorMessage,
    this.labelText,
  });

  TextInputType textInputType;
  TextEditingController textController;
  String errorMessage, labelText;


  @override
  Widget build(BuildContext context) {
    bool isError = false;
    return  Container(
      child: TextFormField(
        keyboardType: textInputType,
        style: Theme
              .of(context)
              .textTheme
              .title,
        controller: textController,
        validator: (String value) {
            if (value.isEmpty) {
              return errorMessage;
            }
        },
        decoration: InputDecoration(
          labelStyle: TextStyle(
            color: Colors.grey,
            fontSize: 16.0
          ),
        contentPadding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),  //size of textfield
        errorStyle: TextStyle(
          color: Colors.red,
          fontSize: 15.0
        ),
        border: OutlineInputBorder(
          borderSide:  BorderSide(width:5.0),
          borderRadius: BorderRadius.circular(5.0)
        )
        )
      ),
    );
  }
}


我想从RowTextInput.dart访问位于main.dart中的isError和isButtonPressed变量,并能够分配值。然后main.dart应该能够看到在RowTextInput.dart文件中分配的那些值。

另外,我想将MaterialButton按钮移动到其自己的窗口小部件文件(button.dart)中,但随后我不知道当单击按钮或检查isError和值时,此dart文件将如何与main.dart文件进行交互。按下IS按钮。基本上,我将表单分为不同的组件(文本字段和按钮),并将它们存储在自己的单独文件中。但我希望所有文件main.dart,rowintputtext,button.dart(new)都能看到main.dart中变量的值并更改值。这可能吗?有没有更简单的方法?

预先感谢

3 个答案:

答案 0 :(得分:2)

我还希望将表单分为多个类。这是我做的:


表格

在表单级别传递onSaved函数。

final _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
  return Form(
    key: _formKey,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
          _CustomFormField(
           onSaved: (value) => _myModelForm.field1 = value),
          ),
          _CustomFormField2(
           onSaved: (value) => _myModelForm.field2 = value),
          )
        ),
          RaisedButton(
            onPressed: () {
              // Validate will return true if the form is valid, or false if
              // the form is invalid.
              if (_formKey.currentState.validate()) {
                // Process data.
                _formKey.currentState.save();
                // Observe if your model form is updated
                print(myModelForm.field1);
                print(myModelForm.field2)
              }
            },
            child: Text('Submit'),
        ),
      ],
    ),
  );
}

_CustomFormField1

onSaved函数将作为参数传递。此类可以位于与表单相同的文件中,也可以位于另一个专用文件中。

class _CustomFormField1 extends StatelessWidget {
  final FormFieldSetter<String> onSaved;
  //maybe other properties...


  _CustomFormField1({
    @required this.onSaved,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 10.0),
      child: TextFormField(
        // You can keep your validator here
        validator: (value) {
          if (value.isEmpty) {
            return 'Please enter some text';
          }
          return null;
        },
        onSaved: onSaved,
      ),
    );
  }
}

onSaved一样,如果需要,您可以对focusNodeonFieldSubmittedvalidator进行同样的操作

我希望它将对您和其他人有帮助

答案 1 :(得分:0)

考虑一下。在Flutter中,Button和RawMaterialButton已经在其他文件中。并能够完全按照您的意愿进行操作。

您应该创建一个文件mycustomButtons.dart。
在文件中,您应该创建一个将构建Buttons的类。
但是必须在其构造函数actionSave actionSaveAndContinue中有两个参数。

然后您将在您的主要对象中创建两个功能,例如:

      void _save() {
          setState(() {
              if (_formKey.currentState.validate()) {
                // amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
              //this.displayResult = _calculateTotalReturns();
              }
          })
      }

然后,您应该将创建的函数作为参数传递:

    MyCustomButtons(actionSave: _save, actionSaveAndContinue: _saveAndContinue)

因此,该按钮将具有所有需要的信息来更新main.dart变量。

textField几乎相同。但是您将需要通过验证功能和TextEditingController

您可以查看RawnMaterialButtonTextFormField的字体,以了解它们如何接收(并将)数据从一类传递到另一类。

答案 2 :(得分:0)

也许有一种更优雅的方式来做到这一点,但我目前正在尝试Singletons。请参见下面的代码:

 <p>123</p>   the result willl be ok I mean only 123

检查我如何在AppModel类的更新函数中使用这三个控制器。