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

Flutter实现TextField获焦显光标但不弹出键盘的方法

Flutter实现TextField获焦显示光标但不弹出键盘

我正在开发一个Flutter应用,需求是点击“Entrée”或“Sortie”按钮时,让“Nom” TextField获得焦点并显示光标,但不弹出屏幕键盘,以便通过扫码枪自动向获焦输入框输入文本。

项目配置

name: jtekt_mobile
description: "A new Flutter project."
publish_to: "none"
version: 0.1.0

environment:
  sdk: ">=3.3.3 <4.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0

flutter:
  uses-material-design: true

当前代码

import 'package:flutter/material.dart';
import 'package:jtekt_mobile/models/mean_model.dart';

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

  @override
  State<Mean> createState() => _MeanState();
}

class _MeanState extends State<Mean> {
  bool isInOutSelected = false;
  bool isNameSelected = false;
  bool exitSelected = false;
  bool entrySelected = false;

  Color redColor = Colors.red;
  Color greenColor = Colors.green;
  Color greyColor = Colors.grey;

  List<MeanModel> meanList = [];

  final FocusNode nameFocusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          flex: 1,
          child: Container(
            color: Colors.white,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                ElevatedButton(
                  onPressed: entryButton,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: !isInOutSelected || entrySelected
                        ? greenColor
                        : greyColor,
                  ),
                  child: const Text(
                    "Entrée",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
                ElevatedButton(
                  onPressed: exitButton,
                  style: ElevatedButton.styleFrom(
                    backgroundColor:
                        !isInOutSelected || exitSelected ? redColor : greyColor,
                  ),
                  child: const Text(
                    "Sortie",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ],
            ),
          ),
        ),
        if (isInOutSelected)
          Expanded(
            flex: 5,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Padding(
                  padding: const EdgeInsets.all(10),
                  child: TextField(
                    focusNode: nameFocusNode,
                    decoration: InputDecoration(
                      focusedBorder: OutlineInputBorder(
                        borderSide: BorderSide(
                            color: entrySelected ? greenColor : redColor,
                            width: 4),
                      ),
                      border: const OutlineInputBorder(),
                      labelText: ("Nom"),
                      enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(
                            color: entrySelected ? greenColor : redColor,
                            width: 2),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 20),
                if (isNameSelected)
                  const Padding(
                    padding: EdgeInsets.all(10),
                    child: TextField(
                      decoration: InputDecoration(
                        border: const OutlineInputBorder(),
                        labelText: ("Moyen"),
                        enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.black, width: 2),
                        ),
                      ),
                    ),
                  ),
                const SizedBox(height: 20),
                Expanded(
                  child: SingleChildScrollView(
                    scrollDirection: Axis.vertical,
                    child: Column(
                      children: meanList
                          .map((mean) => ListTile(
                                title: Text(mean.username),
                                subtitle: Text(mean.meanNumber),
                                trailing: const Icon(Icons.delete),
                              ))
                          .toList(),
                    ),
                  ),
                ),
                if (isNameSelected)
                  Center(
                    child: ElevatedButton(
                      onPressed: validation,
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.blue,
                      ),
                      child: const Text(
                        "Valider",
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                const SizedBox(height: 20),
              ],
            ),
          ),
      ],
    );
  }

  void entryButton() {
    setState(() {
      isInOutSelected = true;
      entrySelected = true;
      exitSelected = false;
    });
    nameFocusNode.requestFocus();
  }

  void exitButton() {
    setState(() {
      isInOutSelected = true;
      exitSelected = true;
      entrySelected = false;
    });
    nameFocusNode.requestFocus();
  }

  void validation() {}
}

已尝试的无效方案

  • 调用SystemChannels.textInput.invokeMethod('TextInput.hide')
  • 使用FocusNode.unfocus()
  • 集成input_with_keyboard_control库

可行解决方案

给目标TextField添加两个核心属性,即可实现获焦显示光标但不弹出软键盘的效果:

TextField(
  focusNode: nameFocusNode,
  keyboardType: TextInputType.none, // 禁用软键盘弹出
  showCursor: true, // 确保获焦时显示光标
  decoration: InputDecoration(
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(
          color: entrySelected ? greenColor : redColor,
          width: 4),
    ),
    border: const OutlineInputBorder(),
    labelText: ("Nom"),
    enabledBorder: OutlineInputBorder(
      borderSide: BorderSide(
          color: entrySelected ? greenColor : redColor,
          width: 2),
    ),
  ),
)

原理说明

  • TextInputType.none:Flutter官方提供的键盘类型,会告知系统不需要弹出软键盘,同时保留输入框的焦点状态和光标显示能力。
  • showCursor: true:显式开启光标显示(默认获焦时会显示,显式设置可避免不同平台的行为差异)。

扫码枪模拟的是物理键盘输入,即使软键盘不弹出,获焦的输入框依然可以正常接收扫码枪的文本输入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 03:08:11