我编写了一个自定义文本字段,用于在验证器失去焦点时检查它,其中包含一些 UI,例如错误文本和绿色选中图标。在我需要根据其他 TextField 的数据执行一些自动填充之前,它们工作正常。
当用户填写邮政编码时,将从 ChangeNotifierProvider 视图模型中调用 API 并根据其更新状态
user.prefectureName = data.prefectureName;
user.city = data.city;
user.address = data.address;
notifyListeners();
在 HookConsumerWidget 页面中,我将状态传递到自定义文本字段中,如下所示
OCTextField(
text: user.prefectureName,
labelText: l10n.accountProfileEditPrefectureName,
errorText: "都道府県は必須項目です",
onChanged: (value) => user.prefectureName = value,
validator: (value) => value.isNotEmpty),
OCTextField(
text: user.city,
labelText: l10n.accountProfileEditCity,
errorText: "市区町村は必須項目です",
onChanged: (value) => user.city = value,
validator: (value) => value.isNotEmpty),
OCTextField(
text: user.address,
labelText: l10n.accountProfileEditAddress,
errorText: "丁目・番地は必須項目です",
onChanged: (value) => user.address = value,
validator: (value) => value.isNotEmpty),
但是,当状态更改(user.prefectureName、user.city 和 user.address)时,我的自定义文本字段将无法相应地反映更改。这是我的自定义文本字段代码的一部分
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import '../util/ext/string_ext.dart';
typedef Validator = bool Function(String value);
class OCTextField extends HookWidget {
const OCTextField(
{Key? key,
this.text = "",
this.labelText,
this.hintText,
this.errorText,
this.maxLines = 1,
this.maxLength,
this.sanitise = true,
this.onChanged,
this.validator})
: super(key: key);
final String text;
final String? labelText;
final String? hintText;
final String? errorText;
final int? maxLines;
final int? maxLength;
final bool sanitise;
final ValueChanged<String>? onChanged;
final Validator? validator;
@override
Widget build(BuildContext context) {
final _showError = useState(false);
final _controller = useTextEditingController(text: text);
final _checkIcon;
final unchecked =
const Icon(Icons.check_circle_outline, color: Colors.black26);
final checked = const Icon(Icons.check_circle, color: Colors.green);
if (validator != null) {
_checkIcon = useState(validator!(_controller.text) ? checked : unchecked);
} else {
_checkIcon = useState(checked);
}
return Focus(
child: TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(1.0),
),
suffixIcon: _checkIcon.value,
labelText: labelText,
hintText: hintText,
errorText: _showError.value ? errorText : null,
),
maxLines: maxLines,
maxLength: maxLength,
onChanged: onChanged),
onFocusChange: (isFocused) {
if (isFocused) {
_showError.value = false;
_checkIcon.value = unchecked;
} else {
if (sanitise) {
_controller.text = _controller.text.sanitise();
onChanged!(_controller.text.sanitise());
}
if (validator != null) {
_showError.value = !validator!(_controller.text);
}
_checkIcon.value = _showError.value ? unchecked : checked;
}
});
}
}
我实际上阅读了 useTextEditingController(text: text) 的文档,它不会对文本更改做出反应。我尝试替换useTextEditingController
为TextEditingController
,但它以某种奇怪的行为起作用 - 即使我删除了反射的预填充文本并移动另一个字段,文本也会再次出现;光标表现得很奇怪,当我单击该字段时,它从预填充文本的开头开始。
当我继承 TextField 类并将 TextControllerEditor 直接初始化为 TextField 实例时,它可以完美地工作而没有奇怪的问题。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class OutlinedTextField extends TextField {
OutlinedTextField(
{String? labelText,
String? text,
String? errorText,
String? hintText,
TextInputType keyboardType = TextInputType.text,
int maxLines = 1,
Icon? icon,
List<TextInputFormatter>? inputFormatters,
ValueChanged<String>? onChanged,
isDense = false})
: super(
controller: text == null ? null : TextEditingController(text: text),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(1.0),
),
labelText: labelText,
hintText: hintText,
errorText: errorText,
prefixIcon: icon,
isDense: isDense),
keyboardType: keyboardType,
maxLines: maxLines,
inputFormatters: inputFormatters,
onChanged: onChanged,
);
}
使用这种方法,我无法获得控制器。我使用组合而不是继承重构自定义文本字段的原因是访问 controller.text 以进行验证 UI。我在这里犯了一些严重的错误或误解了这个概念吗?我无法弄清楚这种奇怪的行为。