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

如何拆分TextFormField并在SplittedBox中输入字母数字组合的车牌号?

实现拆分式车牌号输入框(Flutter)

拆分式车牌号输入框示例

需要实现一个拆分式文本输入框,用于输入由字母和数字组成的车牌号,同时解决拆分输入框中输入这类字符的问题。以下是现有代码片段:

Container(
 color: Colors.grey[200],
 padding: EdgeInsets.all(20),
child: Column(
  mainAxisSize: MainAxisSize.min,
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Text(
   "Vehicle Number:",
    style: TextStyle(
   fontWeight: FontWeight.bold,
   ),
  ),
    Padding(
      padding: const EdgeInsets.all(10),
      child: TextFormField(
        controller: vehicleNo,
        style: const TextStyle(
            fontWeight: FontWeight.bold),
        decoration: InputDecoration(
          border: UnderlineInputBorder(
            borderRadius:
                BorderRadius.circular(5.0),
            borderSide: const BorderSide(
              width:  0,
              style: BorderStyle.none,
            ),
          ),
          fillColor: Colors.white,
          filled: true,
          //labelText: 'Vehicle Number.*',
          contentPadding:
              const EdgeInsets.symmetric(
                  vertical: 10.0,
                  horizontal: 10.0),
        ),
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Please enter vehicle number';
          } else {

解决方案

拆分式输入框可以通过多个TextFormField组合实现,配合焦点自动切换、输入限制来完成车牌号输入需求,具体实现代码如下:

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

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

  @override
  State<VehicleNumberInput> createState() => _VehicleNumberInputState();
}

class _VehicleNumberInputState extends State<VehicleNumberInput> {
  // 对应7位车牌号的输入控制器列表
  final List<TextEditingController> _inputControllers = List.generate(7, (index) => TextEditingController());
  // 每个输入框的焦点节点列表
  final List<FocusNode> _focusNodes = List.generate(7, (index) => FocusNode());

  @override
  void dispose() {
    // 销毁控制器和焦点节点,避免内存泄漏
    for (var controller in _inputControllers) {
      controller.dispose();
    }
    for (var node in _focusNodes) {
      node.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.grey[200],
      padding: const EdgeInsets.all(20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            "车牌号:",
            style: TextStyle(
              fontWeight: FontWeight.bold,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(10),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: List.generate(7, (index) {
                return SizedBox(
                  width: 40,
                  child: TextFormField(
                    controller: _inputControllers[index],
                    focusNode: _focusNodes[index],
                    style: const TextStyle(fontWeight: FontWeight.bold),
                    decoration: InputDecoration(
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(5.0),
                      ),
                      fillColor: Colors.white,
                      filled: true,
                      contentPadding: const EdgeInsets.symmetric(
                          vertical: 10.0, horizontal: 10.0),
                    ),
                    keyboardType: TextInputType.text,
                    maxLength: 1,
                    // 只允许输入字母和数字
                    inputFormatters: [
                      FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9]')),
                    ],
                    onChanged: (value) {
                      // 输入字符后自动跳转到下一个输入框
                      if (value.isNotEmpty && index < 6) {
                        FocusScope.of(context).requestFocus(_focusNodes[index + 1]);
                      }
                      // 删除字符后自动回到上一个输入框
                      if (value.isEmpty && index > 0) {
                        FocusScope.of(context).requestFocus(_focusNodes[index - 1]);
                      }
                    },
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return '请输入';
                      }
                      return null;
                    },
                  ),
                );
              }),
            ),
          ),
          // 点击获取完整车牌号
          ElevatedButton(
            onPressed: () {
              String fullVehicleNumber = _inputControllers.map((e) => e.text).join();
              print("完整车牌号:$fullVehicleNumber");
            },
            child: const Text('提交'),
          )
        ],
      ),
    );
  }
}

核心实现要点

  • 拆分输入框:用7个TextFormField对应普通车牌号的7位结构,每个输入框限制最多输入1个字符
  • 焦点自动切换:通过onChanged监听输入状态,输入完成后自动跳转下一个输入框,删除时回到上一个,提升输入流畅度
  • 输入内容限制:借助FilteringTextInputFormatter只允许输入字母和数字,符合车牌号的字符规则
  • 资源管理:为每个输入框单独创建控制器和焦点节点,并在页面销毁时释放,避免内存泄漏

内容的提问来源于stack exchange,提问作者Bhavya N

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:46:15