自定义文本字段中的 TextEditingController 行为
TextEditingController behaviour in custom text field
我编写了一个自定义文本字段,用于在失去焦点时检查验证器,其中包含一些 UI 例如错误文本和绿色选中图标。在我需要根据其他 TextField 的数据执行一些自动填充之前,它们工作正常。
当用户填写邮政编码时,API 将从 ChangeNotifierProvider 视图模型中调用并根据
更新状态
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 class 并将 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。我在这里犯了一些严重的错误或误解了这个概念吗?我无法弄清楚这种奇怪的行为。
- 您必须在自定义文本字段中添加可重复使用的控制器
- 注意:您必须始终为每个文本字段创建一个单独的控制器
class CustomTextField extends StatelessWidget {
// created custom controller
TextEditingController controller;
String text;
CustomTextField({
required this.controller,
required this.text
});
@override
Widget build(BuildContext context) {
return TextField();
}
}
- 然后为每个文本文件创建一个 textEditingController 并在 oninit 函数中初始化它。
late TextEditingController text1 ;
late TextEditingController text2 ;
- 在自定义文本字段中使用控制器
CustomTextField(controller: text1 ,text: "text1",),
CustomTextField(controller: text2 ,text: "text2",)
我编写了一个自定义文本字段,用于在失去焦点时检查验证器,其中包含一些 UI 例如错误文本和绿色选中图标。在我需要根据其他 TextField 的数据执行一些自动填充之前,它们工作正常。
当用户填写邮政编码时,API 将从 ChangeNotifierProvider 视图模型中调用并根据
更新状态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),
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 class 并将 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。我在这里犯了一些严重的错误或误解了这个概念吗?我无法弄清楚这种奇怪的行为。
- 您必须在自定义文本字段中添加可重复使用的控制器
- 注意:您必须始终为每个文本字段创建一个单独的控制器
class CustomTextField extends StatelessWidget {
// created custom controller
TextEditingController controller;
String text;
CustomTextField({
required this.controller,
required this.text
});
@override
Widget build(BuildContext context) {
return TextField();
}
}
- 然后为每个文本文件创建一个 textEditingController 并在 oninit 函数中初始化它。
late TextEditingController text1 ;
late TextEditingController text2 ;
- 在自定义文本字段中使用控制器
CustomTextField(controller: text1 ,text: "text1",),
CustomTextField(controller: text2 ,text: "text2",)