2

我正在尝试创建一个具有如下disabled属性的 Textbutton 小部件:

class AppTextButton extends StatelessWidget {
  final String title;
  final void Function(BuildContext context) onPress;
  final EdgeInsetsGeometry margin;
  final EdgeInsetsGeometry padding;
  final double borderRadius;
  final Color backgroundColor;
  final Image? leadingIcon;
  final Image? trailingIcon;
  final TextStyle? textStyle;
  final bool disabled;

  AppTextButton(this.title, this.onPress,
      {this.margin = const EdgeInsets.all(0),
      this.padding = const EdgeInsets.all(12),
      this.borderRadius = 0,
      this.leadingIcon,
      this.trailingIcon,
      this.textStyle,
      this.disabled = false,
      this.backgroundColor = const Color(0xFFFFFFFF)});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: margin,
      child: TextButton(
        style: ButtonStyle(
            shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(borderRadius))),
            backgroundColor: MaterialStateProperty.all(backgroundColor)),
        child: Row(
          children: [
            if (this.leadingIcon != null) ...[this.leadingIcon!],
            Expanded(
              child: Padding(
                padding: padding,
                child:
                    Text(title, textAlign: TextAlign.center, style: textStyle),
              ),
            ),
            if (this.trailingIcon != null) ...[this.trailingIcon!]
          ],
        ),
        onPressed: () => !disabled ? onPress(context) : null,
      ),
    );
  }
}

在我的屏幕上,我声明我的 formKey 和我的表单如下:

class LoginScreen extends AppBaseScreen {
  LoginScreen({Key? key}) : super(key: key);

  final _formKey = GlobalKey<FormState>();

@override
  Widget build(BuildContext context) {
              Form(
                  key: _formKey,
                  child: Obx(
                    () => AppTextInput(
                      "Please input passcode",
                      _passwordController,
                      borderRadius: 8,
                      fillColor: Color(0xFFF6F4F5),
                      keyboardType: TextInputType.number,
                      errorMessage: _c.errorLoginConfirm.value,
                      isObscure: true,
                      onChange: _onInputChange,
                      maxLength: 6,
                      margin: EdgeInsets.only(top: 12, left: 20, right: 20),
                      validator: (text) {
                        if (text != null && text.length > 0) {
                          if (text.length < 6) {
                            return "Passcode must have at least 6 digits";
                          }
                        }
                      },
                    ),
                  )),

我将在屏幕底部有一个按钮,我!_formKey.currentState!.validate()在禁用字段中传递

AppTextButton("Login", _onLogin,
                  margin: EdgeInsets.fromLTRB(24, 24, 24, 8),
                  backgroundColor: Color(0xFFFF353C),
                  disabled: !_formKey.currentState!.validate(),
                  textStyle: TextStyle(color: Colors.white),
                  borderRadius: 8),

但是,formKey.currentState 为 null 并在每次打开屏幕时抛出以下错误。 Null check operator used on a null value

我在这里做错了什么?先感谢您!

4

3 回答 3

0

传递前需要保存表单状态,

final FormState formState = _formKey.currentState;
formState.save();


onPressed: () {
                FocusScope.of(context).requestFocus(FocusNode());
                final FormState formState = _formKey.currentState;
                if (formState.validate()) {
                  formState.save();
                  onPress(context);
                }
              },
于 2021-09-04T03:05:03.727 回答
0

在您的情况下,您应该知道小部件的构建过程(假设您有Botton小部件和Input小部件):

  1. Botton并且Input正在建立初始状态。两种状态都还没有准备好被读取和使用
  2. BottonInput建成。各州已准备好阅读。
  3. 用户与Input. 如果值通过验证器,则Input必须调用以重建其状态Button
  4. Botton重建。

对于该过程,您应该更改代码,例如:

  1. 获取和修改Buttoninside的状态Input
  2. 通知Button重建

有很多方法可以处理小部件之间的状态管理。我只是将 AppTextButton 更改为 Statefultwidget 来实现它。

...
final _buttonKey = GlobalKey<_AppTextButtonState>();
...
  AppTextButton(key: _buttonKey)
...


class AppTextButton extends StatefulWidget {
  final bool initDisable;

  AppTextButton({
    this.initDisable = false,
    Key? key,
  }) : super(key: key);

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

class _AppTextButtonState extends State<AppTextButton> {
  var disable;

  @override
  void initState() {
    disable = widget.initDisable;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return TextButton(child: Text('Button'), onPressed: disable ? null : () {});
  }

  void enableButton() {
    setState(() {
      disable = false;
    });
  }

  void disableButton() {
    setState(() {
      disable = true;
    });
  }
}


class LoginScreen extends StatelessWidget {
  LoginScreen({Key? key}) : super(key: key);

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: TextFormField(
        autovalidateMode: AutovalidateMode.onUserInteraction,
        validator: (text) {
          if (text != null && text.length > 0) {
            if (text.length < 6) {
              return "Passcode must have at least 6 digits";
            }
          }
        },
        onChanged: (v) {
          if (_formKey.currentState?.validate() ?? false) {
            _buttonKey.currentState?.enableButton();
          } else {
            _buttonKey.currentState?.disableButton();
          }
        },
      ),
    );
  }
}
于 2021-09-10T01:53:21.253 回答
0

我认为这个问题是因为所有的小部件都是同时创建的,所以调用它_formKey.currentState时仍然为空。AppTextButton

您需要创建一个单独的控制器来控制按钮的状态并将其添加到验证器,如下所示:

validator: (text) {

                     if (text != null && text.length > 0) {
                        if (text.length < 6) {
                           buttonDisableController = true;
                           return "Passcode must have at least 6 digits";
                        }
                     }
                     buttonDisableController = false;
                     return null;
                  },
于 2021-09-04T07:05:11.827 回答