TextField输入框内容神奇的被清空了?-- 解释bug

401 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

前言

看过我之前文章的小伙伴应该都知道,由于公司业务的需求,最近一直在搞Flutter项目,因为之前也没有接触过,所以也是在踩坑中慢慢学习吧。

这不,又遇见了个神奇的bug--TextField输入框内容被清空了

前置知识点--TextField

Flutter中通过TextField组件来实现同Web端的Input标签一样效果的输入框。 这里主要介绍其中的一个属性obscureText,后续的密码框的显隐就是通过控制该属性的Boolen值来实现的。

  • obscureText:是否隐藏正在编辑的文本,如用于输入密码的场景等,文本内容会用“•”替换。为true时会显示为“•”。

业务需求是: 默认输入密码是隐藏文本的状态(显示成小圆点),当点击输入框右边的图标时,可以动态切换输入框的文本的显示状态(正常文本或隐藏文本的小圆点)。

如图,本意是想当点击输入框右侧的小图标来动态控制密码框文本的显示隐藏的。结果我们会发现,每次输入完内容后,想点击小图标来切换显隐,会直接把文本给清空了。

输入框内容莫名被清空.gif

首先强调一点,因为我是封装了TextField,所以才会导致这个奇怪的bug。

以下是我实现这个效果伪代码:

  1. 封装的TextField,注意这里是使用Flutter原生的状态组件来保存数据状态的,这也是导致出现bug的前提。
class ExInput extends StatefulWidget {
  ExInput({
    Key? key,
    ...
    this.val,
    this.hiddenPassword = false,
    required this.onChanged,
    ...
  }) : super(key: key);
  final ValueChanged<dynamic> onChanged;
  bool hiddenPassword;
  final dynamic val;

  @override
  State<ExInput> createState() => _ExInputState();
}

class _ExInputState extends State<ExInput> {
  @override
  Widget build(BuildContext context) {
    return TextField(
            obscureText: widget.hiddenPassword,
            onChanged: (val) {
              widget.onChanged(val);
            },
            controller: TextEditingController.fromValue(
                TextEditingValue(text: widget.val ?? '')),  //这里的widget.val是重要点
          );
  }
}
  1. 在登录页中使用

// 使用Getx来管理的登录页的数据
class LoginData extends GetxController {
  RxBool showHidden = true.obs;
  //切换文本状态
  updateShowHidden() {
    showHidden.value = !showHidden.value;
  }
}
//实例化
final LoginData ld = Get.put(LoginData());
  
class Login extends StatefulWidget {
  const Login({Key? key}) : super(key: key);

  @override
  State<Login> createState() => _LoginState();
}

class _LoginState extends State<Login> {
  @override
  Widget build(BuildContext context) {
    return Obx(() => ExInput(
      hiddenPassword: ld.showHidden.value,
      onChanged: (val) => {},
      suffixWidget: GestureDetector(
            onTap: () => ld.updateShowHidden(),
            child: Container(
              width: 120.w,
              margin: EdgeInsets.only(right: 16.w),
              alignment: Alignment.centerRight,
              child: Image.asset('assets/images/home/eye-slash.png',
                        width: 16.w, height: 16.h);
            ),
          ),      
    ));  
}

以上就是实现上图bug的伪代码。主要思路就是: 通过Getx创建一个变量,用于控制密码框的显隐(传递给ExInput类),并用Obx来实现数据改变界面更新的效果,然后在点击时触发updateShowHidden方法,更改变量的值,达到动态控制TextField的obscureText属性。