我正在尝试创建一个具有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";
}
}
},
),
)),
我将在屏幕底部有一个按钮,我在disabled字段中传递!_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
我在这里做错了什么?提前感谢!
您需要在传递之前保存表单状态,
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);
}
},
我认为这个问题是由于所有的小部件都是在同一时间创建的,所以当AppTextButton
调用它时,_formKey.currentState
仍然是null。
您需要创建一个单独的控制器来控制按钮的状态,并将其添加到验证器中,如下所示:
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;
},
在您的情况下,您应该知道如何构建小部件的过程(假设您有Botton
小部件和Input
小部件):
Botton
和Input
正在构建初始状态。这两个状态都还没有准备好被读取和使用 构建Botton
和Input
。状态准备好读取。- 用户与
Input
交互。如果值通过验证器 , Botton
rebuild.
Input
必须调用Button
来重建其状态对于这个过程,你应该像这样修改你的代码:
- 获取并修改
Input
中Button
的状态 - 通知
Button
重建
有许多方法可以处理小部件之间的状态管理。我只需将AppTextButton更改为statfultwidget即可实现。
...
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();
}
},
),
);
}
}