自定义文本字段中的 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。我在这里犯了一些严重的错误或误解了这个概念吗?我无法弄清楚这种奇怪的行为。

  1. 您必须在自定义文本字段中添加可重复使用的控制器
  2. 注意:您必须始终为每个文本字段创建一个单独的控制器
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();
  }
}
  1. 然后为每个文本文件创建一个 textEditingController 并在 oninit 函数中初始化它。
late TextEditingController text1 ;
  late TextEditingController text2 ;
  1. 在自定义文本字段中使用控制器
 CustomTextField(controller: text1 ,text: "text1",),
 CustomTextField(controller: text2 ,text: "text2",)