我正在使用CustomFormField类来定制TextFormField的默认行为。我想做的事情之一是移动errorText的位置,以防止它在发生错误时调整表单上其他字段的位置。通过使用堆栈并重新定位errorText使其出现在字段的下边界而不是下面的几个像素,我已经实现了一半的目标。不幸的是,默认行为仍然保留空间,其他字段仍然移动。
Text Fields without error condition
Text Fields with error condition
如您所见,errorText不再占用空间,但TextFormField的默认行为仍然占用空间。
有什么办法可以防止这种情况发生吗?
这是一个有点长,这仍然是一个正在进行中的工作,但这里是我使用的代码。
class CustomFormField extends StatefulWidget {
final GlobalKey formKey;
final TextEditingController controller;
final FocusNode currentFocusNode;
final FocusNode futureFocusNode;
final TextInputType inputType;
final TextInputAction inputAction;
final bool allowShowPassword;
final bool enabled;
final bool autoFocus;
final String labelText;
final String hintText;
final FormFieldValidator<String>? validator;
final Function? onChanged;
final FormFieldSetter<String>? onSaved;
const CustomFormField(
{super.key,
required this.formKey,
required this.controller,
required this.currentFocusNode,
required this.futureFocusNode,
this.inputType = TextInputType.text,
this.inputAction = TextInputAction.next,
this.allowShowPassword = true,
this.enabled = true,
this.autoFocus = false,
this.labelText = '',
this.hintText = '',
this.validator,
this.onChanged,
this.onSaved});
@override
State<CustomFormField> createState() => _CustomFormFieldState();
}
class _CustomFormFieldState extends State<CustomFormField> {
bool _passwordHidden = true;
bool onError = false;
String _errorText = '';
@override
Widget build(BuildContext context) {
// grab the application theme to use when colouring text fields
ThemeData theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Stack(
children: [
TextFormField(
enabled: widget.enabled,
autofocus: widget.autoFocus,
textInputAction: widget.inputAction,
onEditingComplete: () =>
FocusScope.of(context).requestFocus(widget.futureFocusNode),
focusNode: widget.currentFocusNode,
keyboardType: widget.inputType,
obscureText: (widget.inputType == TextInputType.visiblePassword &&
_passwordHidden)
? _passwordHidden
: false,
controller: widget.controller,
validator: (value) {
String? errorText = widget.validator!.call(value);
if (errorText != null && Static.formIsValid) {
Static.formIsValid = false;
widget.currentFocusNode.requestFocus();
setState(() {
onError = true;
_errorText = errorText;
});
} else {
setState(() {
onError = false;
_errorText = '';
});
}
// the validator still needs us to return null if there was no error
// but if there is an error return empty string
return errorText == null ? null : '';
},
onSaved: widget.onSaved,
onChanged: (value) {
if (widget.onChanged != null) {
widget.onChanged!.call(value);
}
},
style: TextStyle(
color: widget.enabled
? Constants.formFieldColor
: theme.disabledColor,
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Ariel'),
decoration: InputDecoration(
labelText: widget.labelText,
hintText: widget.hintText,
hintStyle: const TextStyle(color: Colors.white38),
contentPadding: const EdgeInsets.symmetric(horizontal: 25),
// constraints: const BoxConstraints(maxHeight: 40, minHeight: 40),
filled: true,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
errorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.red)),
focusedErrorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
disabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(color: Colors.black)),
alignLabelWithHint: true,
focusColor: Colors.black,
suffixIcon: widget.inputType == TextInputType.visiblePassword &&
widget.allowShowPassword
? InkWell(
onTap: () {
setState(() {
_passwordHidden = !_passwordHidden;
});
},
child: Icon(
_passwordHidden
? Icons.visibility_off_outlined
: Icons.visibility_outlined,
color: Constants.passwordShowHideIconColor,
size: 18,
),
)
: null,
),
),
// this repositions the errorText to appear just on top of the lower border
onError
? Positioned(
bottom: 17,
left: 25,
child: Container(
height: 15,
decoration: const BoxDecoration(color: Colors.white),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Text(_errorText,
style: const TextStyle(
color: Colors.red,
fontSize: 13,
fontStyle: FontStyle.normal)),
),
),
)
: Container(),
],
),
);
}
}
我尝试过的一件事是将所有字段都 Package 在一个SizedBox中,这确实阻止了其他字段改变它们的位置,但它的副作用是缩小了包含错误的字段的大小,因为它总是希望为errorText保留空间。
任何帮助都将不胜感激。
1条答案
按热度按时间m1m5dgzv1#
已解决:
我可以通过添加以下内容来解决这个问题:
这将阻止字段为错误文本占用额外空间。