виджет шагового двигателя flutter - проверка полей на отдельных этапах

Я использую шаговый виджет, чтобы собирать информацию от пользователя и проверять ее, мне нужно вызывать API на каждом шаге, следовательно, проверять каждое поле на шаге на каждой кнопке продолжения ... я использую состояние формы и виджет формы, но проблема в том, что он проверяет целые поля на всех этапах в степпере ... как я могу проверить только отдельный шаг в степпере? Я просмотрел документацию в классах Stepper и State в stepper.dart, но там нет поддерживающей функции

Ниже приведен код

class SubmitPayment extends StatefulWidget {


 SubmitPayment({Key key, this.identifier, this.amount, this.onResendPressed})
      : super(key: key);

  final String identifier;
  final String amount;
  final VoidCallback onResendPressed;

  @override
  State<StatefulWidget> createState() {
    return _SubmitPaymentState();
  }
}

class _SubmitPaymentState extends State<SubmitPayment> {
  final GlobalKey<FormState> _formKeyOtp = GlobalKey<FormState>();
  final FocusNode _otpFocusNode = FocusNode();
  final TextEditingController _otpController = TextEditingController();
  bool _isOTPRequired = false;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 8.0),
      child: Form(
          key: _formKeyOtp,
          child: Column(children: <Widget>[
            Center(
                child: Padding(
                    padding:
                        EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
                    child: Text(
                      Translations.of(context).helpLabelOTP,
                      style: TextStyle(
                          color: Theme.of(context).primaryColor,
                          fontStyle: FontStyle.italic),
                    ))),
            CustomTextField(
              icon: Icons.vpn_key,
              focusNode: _otpFocusNode,
              hintText: Translations.of(context).otp,
              labelText: Translations.of(context).otp,
              controller: _otpController,
              keyboardType: TextInputType.number,
              hasError: _isOTPRequired,
              validator: (String t) => _validateOTP(t),
              maxLength: AppConstants.otpLength,
              obscureText: true,
            ),
            Center(
                child: ButtonBar(
              mainAxisSize: MainAxisSize.max,
              alignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  child: Text(Translations.of(context).resendOtpButton),
                  color: Colors.white,
                  textColor: Theme.of(context).primaryColor,
                  onPressed: widget.onResendPressed,
                ),
                RaisedButton(
                  child: Text(
                    Translations.of(context).payButton,
                  ),
                  onPressed: _doPullPayment,
                ),
              ],
            )),
          ])),
    );
  }

  String _validateOTP(String value) {
    if (value.isEmpty || value.length < AppConstants.otpLength) {
      setState(() => _isOTPRequired = true);
      return Translations.of(context).invalidOtp;
    }
    return "";
  }

  bool _validateOtpForm() {
    _formKeyOtp.currentState.save();
    return this._formKeyOtp.currentState.validate();
  }

  Future<void> _doPullPayment() async {
    setState(() {
      _isOTPRequired = false;
    });

    if (!_validateOtpForm()) return false;

    try {
      setState(() {
        _isOTPRequired = false;
      });
      showDialog(
        barrierDismissible: false,
        context: context,
        builder: (context) => AlertDialog(
              content: ListTile(
                leading: CircularProgressIndicator(),
                title: Text(Translations.of(context).processingPaymentDialog),
              ),
            ),
      );

      TransactionApi api =
          TransactionApi(httpDataSource, authenticator.sessionToken);
      String responseMessage = await api.doPullPayment(
          widget.identifier,
          widget.amount,
          _otpController.text,
          TransactionConstants.transactionCurrency);

      Navigator.of(context).pop();
      await showAlertDialog(
          context, Translations.of(context).pullPayment, '$responseMessage');
      Navigator.pop(context);
    } catch (exception) {
      await showAlertDialog(context, Translations.of(context).pullPayment,
          '${exception.message}');
      Navigator.of(context).pop();
    }
  }

person Sana.91    schedule 08.07.2018    source источник
comment
также не нашел, могу ли я проверить валидацию в отдельных полях формы в form.dart   -  person Sana.91    schedule 08.07.2018


Ответы (2)


Используйте отдельный Form для каждого шага. Используйте список GlobalKey<FormState>, который можно проиндексировать на основе _currentStep, затем вызовите validate() в onStepContinue:

List<GlobalKey<FormState>> _formKeys = [GlobalKey<FormState>(), GlobalKey<FormState>(), …];
…

Stepper(
  currentStep: _currentStep,
  onStepContinue: () {
    setState(() {
      if (_formKeys[_currentStep].currentState.validate()) {
        _currentStep++;
      }
    });
  },
  steps: 
  Step(
    child: Form(key: _formKeys[0], child: …),

Очевидно, вам нужно будет проверить последний шаг и save вместо validate в конце :)

person Derek Lakin    schedule 13.08.2018
comment
Я делал только это, проблема заключалась в функции проверки, которая возвращала пустую строку вместо нуля, что вызывало проблему, пожалуйста, проверьте мой ответ для подробностей - person Sana.91; 28.08.2018
comment
Как вы поняли (ниже), вам нужно вернуть null, а не пустую строку из метода проверки. Если у вас нет явного оператора возврата, это дает тот же конечный результат. - person Derek Lakin; 02.09.2018

Итак, я решил это следующим образом:

Проблема заключалась в том, что я возвращал * пустую строку ("") *, если моя логика действительна, тогда как метод validate для FormState ожидает, что каждый метод проверки, связанный с TextFormField, вернет null, если проверка пройдена.

я изменился после

 String _validateOTP(String value) {
    if (value.isEmpty || value.length < AppConstants.otpLength) {
      setState(() => _isOTPRequired = true);
      return Translations.of(context).invalidOtp;
    }
    return "";
  }

to

  String _validateOTP(String value) {
if (value.isEmpty || value.length < AppConstants.otpLength) {
  setState(() => _isOTPRequired = true);
  return Translations.of(context).invalidOtp;
}
return null;

}

и тогда все работало нормально.

Подробную информацию см. По этой ссылке " Если есть ошибка с информацией, предоставленной пользователем, функция валидатора должна вернуть строку, содержащую сообщение об ошибке. Если ошибок нет, функция не должна вернуть что-нибудь. "

person Sana.91    schedule 28.08.2018
comment
Вы можете достичь того же конечного результата, не имея никакого оператора возврата в допустимом случае (т.е. просто удалите часть return null;) :) - person Derek Lakin; 02.09.2018
comment
@DerekLakin, который вызовет некрасивое предупреждение компилятора: предупреждение: эта функция объявляет возвращаемый тип String, но не заканчивается оператором возврата. (missing_return в file.dart: 166) - person Sana.91; 09.09.2018
comment
Извини да. Я думал о встроенном корпусе, а не о отдельной функции. Честно говоря, я думаю, что компилятор должен выдавать такое же предупреждение и для inline :) - person Derek Lakin; 10.09.2018