You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中TextFormField首5字符模糊显示及原文本保留问题求助

解决方案

核心思路

别直接用replaceRange()修改覆盖原始文本,核心是把原始明文和前端显示的模糊文本分开维护:

  • 用_originalText变量全程保存用户输入的真实内容
  • 动态生成模糊后的displayText作为输入框的显示内容
  • 通过TextEditingController监听所有输入操作,根据用户的输入动作(新增、删除、修改)更新原始文本,再同步生成最新的模糊显示文本

完整代码实现

import 'package:flutter/material.dart';
import 'dart:math';

class ObscureTextInput extends StatefulWidget {
  const ObscureTextInput({super.key});

  @override
  State<ObscureTextInput> createState() => _ObscureTextInputState();
}

class _ObscureTextInputState extends State<ObscureTextInput> {
  late TextEditingController _inputController;
  String _originalText = ''; // 存储真实输入的明文

  @override
  void initState() {
    super.initState();
    _inputController = TextEditingController();
    _inputController.addListener(_updateTextContent);
  }

  @override
  void dispose() {
    _inputController.dispose();
    super.dispose();
  }

  // 处理输入变化,同步更新原始文本和显示文本
  void _updateTextContent() {
    final currentDisplay = _inputController.text;
    final originalLen = _originalText.length;
    final displayLen = currentDisplay.length;

    if (displayLen > originalLen) {
      // 用户新增字符:把新增部分追加到原始文本
      final addedStr = currentDisplay.substring(originalLen);
      _originalText += addedStr;
    } else if (displayLen < originalLen) {
      // 用户删除字符:截断原始文本到对应长度
      _originalText = _originalText.substring(0, displayLen);
    } else {
      // 用户修改中间字符:找到修改位置,更新原始文本对应内容
      final diffIndex = _getFirstDiffIndex(currentDisplay, _makeDisplayText(_originalText));
      if (diffIndex != -1) {
        _originalText = _originalText.replaceRange(
          diffIndex,
          diffIndex + 1,
          currentDisplay[diffIndex],
        );
      }
    }

    // 生成最新模糊文本并同步到输入框
    final newDisplay = _makeDisplayText(_originalText);
    if (_inputController.text != newDisplay) {
      // 避免循环触发监听,用copyWith更新控制器状态
      _inputController.value = _inputController.value.copyWith(
        text: newDisplay,
        selection: TextSelection.collapsed(offset: _inputController.selection.end),
      );
    }

    // 这里可以添加原始文本的业务逻辑,比如提交、存储等
    print('当前原始明文:$_originalText');
  }

  // 生成模糊显示文本:前5位替换为X,其余保留
  String _makeDisplayText(String original) {
    if (original.length <= 5) {
      return 'X' * original.length;
    } else {
      return 'XXXXX${original.substring(5)}';
    }
  }

  // 找到两个字符串第一个不同的位置
  int _getFirstDiffIndex(String a, String b) {
    final minLen = min(a.length, b.length);
    for (int i = 0; i < minLen; i++) {
      if (a[i] != b[i]) return i;
    }
    return a.length == b.length ? -1 : minLen;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('模糊文本输入示例')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: TextFormField(
          controller: _inputController,
          decoration: const InputDecoration(
            hintText: '请输入内容',
            border: OutlineInputBorder(),
          ),
        ),
      ),
    );
  }
}

关键说明

  1. 状态完全分离:_originalText独立于显示文本,任何输入操作都不会覆盖或丢失真实内容
  2. 精准监听输入:通过控制器的listener捕捉所有输入动作,针对性更新原始文本
  3. 避免循环触发:更新显示文本时先判断是否需要修改,用value.copyWith避免无限触发监听
  4. 兼容多场景:支持字符新增、删除、中间修改等常见操作,全程保留原始明文的完整性

内容的提问来源于stack exchange,提问作者Prajwal Shinde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:13:23