0

我是新来的颤振,任何帮助将不胜感激。

我在两个不同的屏幕上有两个单独的表格。单击“下一步”按钮验证表单并Navigator.push()使用第二个表单运行到我的下一个屏幕,之后如果我填写第二个表单的 TextFormFields 并初始化保存然后Navigator.pop()返回到第一个表单,第一个表单中的数据页面仍然填写,但是一旦我再次运行 Navigator.push() 返回到第二个表单,TextFormFields 是空的。

我的目的是让用户数据在TextFormFields两个表单中输入后,在不同的屏幕中来回导航。

我尝试initialValue在 TextFormFields 上使用,但没有奏效。

要导航回来,我正在使用运行后自动创建的后退按钮Navigator.push

这是第一页:

import '../screens/contact_details_screen.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class PersonalDetailsForm extends StatefulWidget {
  @override
  _PersonalDetailsFormState createState() => _PersonalDetailsFormState();
}

class _PersonalDetailsFormState extends State<PersonalDetailsForm> {
  String _title;
  String _firstName;
  String _middleName;
  String _surname;
  String _age;
  String _gender;
  String _dateOfBirth;

  DateTime selectedDate = DateTime.now();
  TextEditingController _date = new TextEditingController();

  final GlobalKey<FormState> _personalDetailsFormKey = GlobalKey<FormState>();

  Widget _buildTitle() {
    return DropdownButtonFormField(
      items: [
        DropdownMenuItem<String>(
          value: 'Dr',
          child: Text('Dr'),
        ),
        DropdownMenuItem<String>(
          value: 'Miss',
          child: Text('Miss'),
        ),
        DropdownMenuItem<String>(
          value: 'Mr',
          child: Text('Mr'),
        ),
        DropdownMenuItem<String>(
          value: 'Mrs',
          child: Text('Mrs'),
        ),
        DropdownMenuItem<String>(
          value: 'Ms',
          child: Text('Ms'),
        ),
        DropdownMenuItem<String>(
          value: 'Prof.',
          child: Text('Prof.'),
        ),
        DropdownMenuItem<String>(
          value: 'Sir',
          child: Text('Sir'),
        ),
      ],
      validator: (String value) {
        if (value == null) {
          return 'Title is required';
        }
        return null;
      },
      value: _title,
      decoration: InputDecoration(labelText: 'Title'),
      onChanged: (String value) {
        setState(() {
          _title = value;
        });
      },
    );
  }

  Widget _buildFirstName() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'First Name'),
      keyboardType: TextInputType.name,
      validator: (String value) {
        if (value.isEmpty) {
          return 'First name is required';
        }
        return null;
      },
      onSaved: (String value) {
        _firstName = value;
      },
    );
  }

  Widget _buildMiddleName() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Middle Name'),
      keyboardType: TextInputType.name,
      onSaved: (String value) {
        _middleName = value;
      },
    );
  }

  Widget _buildSurname() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Surname Name'),
      keyboardType: TextInputType.name,
      validator: (String value) {
        if (value.isEmpty) {
          return 'Surname name is required';
        }
        return null;
      },
      onSaved: (String value) {
        _surname = value;
      },
    );
  }

  Widget _buildAge() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Age'),
      keyboardType: TextInputType.number,
      validator: (String value) {
        int age = int.tryParse(value);

        if (value.isEmpty) {
          return 'Age is required';
        }
        if (age == null || age <= 0) {
          return 'Invalid age';
        }
        return null;
      },
      onSaved: (String value) {
        _age = value;
      },
    );
  }

  Widget _buildGender() {
    return DropdownButtonFormField(
      items: [
        DropdownMenuItem<String>(
          value: 'Male',
          child: Text('Male'),
        ),
        DropdownMenuItem<String>(
          value: 'Female',
          child: Text('Female'),
        ),
        DropdownMenuItem<String>(
          value: 'Other',
          child: Text('Other'),
        )
      ],
      validator: (String value) {
        if (value == null) {
          return 'Gender is required';
        }
        return null;
      },
      value: _gender,
      decoration: InputDecoration(labelText: 'Gender'),
      onChanged: (String value) {
        setState(() {
          _gender = value;
        });
      },
    );
  }

  Widget _buildDateOfBirth() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Date of Birth'),
      validator: (String value) {
        if (value.isEmpty) {
          return 'Date of birth is required';
        }
        return null;
      },
      onTap: () {
        // Below line stops keyboard from appearing
        FocusScope.of(context).requestFocus(new FocusNode());
        // Show Date Picker Here
        _selectDate(context);
      },
      controller: _date,
    );
  }

  Future<Null> _selectDate(BuildContext context) async {
    DateFormat formatter =
        DateFormat('dd/MM/yyyy'); //specifies day/month/year format

    final DateTime picked = await showDatePicker(
        context: context,
        initialDate: selectedDate,
        firstDate: DateTime(1900),
        lastDate: DateTime.now());
    if (picked != null && picked != selectedDate)
      setState(() {
        selectedDate = picked;
        _date.value = TextEditingValue(text: formatter.format(picked));
        _dateOfBirth = _date.text;
      });
  }

  void nextScreen(BuildContext context) {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (_) {
        return ContactDetailsScreen();
      },
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(24),
      child: Form(
        key: _personalDetailsFormKey,
        child: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _buildTitle(),
              _buildFirstName(),
              _buildMiddleName(),
              _buildSurname(),
              _buildAge(),
              _buildGender(),
              _buildDateOfBirth(),
              SizedBox(
                height: 50,
              ),
              SizedBox(
                width: double.infinity,
                child: RaisedButton(
                  color: Theme.of(context).primaryColor,
                  onPressed: () {
                    if (!_personalDetailsFormKey.currentState.validate()) {
                      return;
                    }

                    _personalDetailsFormKey.currentState.save();

                    nextScreen(context);
                  },
                  child: Text(
                    'Next',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

这是第二页:

import 'package:fact_find_v2/screens/testscreen.dart';
import 'package:flutter/material.dart';

class ContactDetailsForm extends StatefulWidget {
  @override
  _ContactDetailsFormState createState() => _ContactDetailsFormState();
}

class _ContactDetailsFormState extends State<ContactDetailsForm> {
  String _email;
  String _phoneNumber;
  String _address;

  final GlobalKey<FormState> _contactDetailsFormKey = GlobalKey<FormState>();

  Widget _buildEmail() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Email'),
      keyboardType: TextInputType.emailAddress,
      validator: (String value) {
        if (value.isEmpty) {
          return 'Email is required';
        }
        if (!RegExp(
                r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
            .hasMatch(value)) {
          return 'Please enter a valid email address';
        }
        return null;
      },
      onSaved: (String value) {
        _email = value;
      },
    );
  }

  Widget _buildPhoneNumber() {
    return TextFormField(
      decoration: InputDecoration(labelText: 'Phone Number'),
      keyboardType: TextInputType.phone,
      validator: (String value) {
        if (value.isEmpty) {
          return 'Phone number is required';
        }
        if (!RegExp(r'(^(?:[+0]9)?[0-9]{8,10}$)').hasMatch(value)) {
          return 'Please enter a valid phone number';
        }
        return null;
      },
      onSaved: (String value) {
        _phoneNumber = value;
      },
    );
  }

  Widget _buildAddress() {
    return TextFormField(
        decoration: InputDecoration(labelText: 'Address'),
        keyboardType: TextInputType.streetAddress,
        // initialValue: _addressController.text,
        validator: (String value) {
          if (value.isEmpty) {
            return 'Address is required';
          }
          return null;
        },
        onSaved: (String value) {
          _address = value;
        });
  }

  void nextScreen(BuildContext context) {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (_) {
          return TestScreen();
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(24),
      child: Form(
        key: _contactDetailsFormKey,
        child: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _buildEmail(),
              _buildPhoneNumber(),
              _buildAddress(),
              SizedBox(
                height: 50,
              ),
              SizedBox(
                width: double.infinity,
                child: RaisedButton(
                  color: Theme.of(context).primaryColor,
                  onPressed: () {
                    if (!_contactDetailsFormKey.currentState.validate()) {
                      return;
                    }
                    _contactDetailsFormKey.currentState.save();
                    nextScreen(
                        context); //this is the next screen which is just used for debugging
                  },
                  child: Text(
                    'Next',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
4

1 回答 1

1

如果您在此处查看 Flutter 文档,您可以看到该Navigator.push()方法返回Future<T>. 当您Navigator.pop()从第二个屏幕调用时,这将完成FutureNavigator.push()方法。

所以基本上你可以将第二个屏幕上的表单数据返回到第一个屏幕,然后在再次按下第二个屏幕的同时你可以将该数据传递到第二个屏幕。

这是你可以做到的 -

  1. 向屏幕添加一个新Map变量以_PersonalDetailsFormState保存结果,Navigator.push()如下所示 -

    Map<String, Object> contactDetailsResult = Map();
    
  2. 您可以将Navigator.push()方法返回的结果保存到 acontactDetailsResult 中,然后将该结果作为参数传递给ContactDetailsScreen.

    void nextScreen(BuildContext context) async{
      contactDetailsResult = await Navigator.of(context).push(MaterialPageRoute(
        builder: (_) {
          return ContactDetailsScreen(
              email: contactDetailsResult["email"] ?? "",
              phoneNumber: contactDetailsResult["phoneNumber"] ?? "",
              address: contactDetailsResult["address"] ?? "",
          );
        },
      ));
    }
    
    
  3. 要弹出路线,您现在必须手动将按钮添加到应用栏或使用WillPopScope. 更多信息可以在这里找到。弹出路由时,您需要像这样从表单中传递数据,这些数据将保存在contactDetailsResult上一步的变量中 -

    Navigator.of(context).pop({
      "email": email,
      "phoneNumber": phoneNumber,
      "address": address,
    });
    
  4. 您可以在官方 Flutter 文档中找到类似的示例

另外,需要注意的一件事——

此解决方案不会将数据保留在应用程序中。如果您弹出第一个屏幕,则两个表单都将被重置。如果您希望在应用程序中保留数据,那么您应该查看shared_preferences插件。教程可以在这里找到。

于 2021-01-05T05:35:24.007 回答