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

如何在TextField获得焦点时显示Tooltip?

解决方案:TextField获焦显示Tooltip及修复长按Tooltip失效问题

一、原长按Tooltip失效原因

TextField组件内置了长按手势(用于弹出文本选择/编辑菜单),其手势优先级高于Tooltip的长按触发逻辑,导致Tooltip无法捕获长按事件,因此长按不生效。

二、实现“获焦时自动显示Tooltip”

基于你已配置FocusNode的前提,可通过以下两种方式实现需求:

方式1:使用TooltipController(Flutter 3.10+ 推荐)

Flutter 3.10及以上版本新增了TooltipController,可手动控制Tooltip的显示与隐藏,结合FocusNode的焦点监听即可实现:

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

  @override
  State<YourTextFieldWidget> createState() => _YourTextFieldWidgetState();
}

class _YourTextFieldWidgetState extends State<YourTextFieldWidget> {
  late FocusNode _textFieldFocusNode;
  late TooltipController _tooltipController;
  // 你的错误提示信息
  final String errorMsg = record.content[widget.index]['error'];

  @override
  void initState() {
    super.initState();
    _textFieldFocusNode = FocusNode();
    _tooltipController = TooltipController();
    
    // 监听焦点变化,控制Tooltip显示/隐藏
    _textFieldFocusNode.addListener(() {
      if (_textFieldFocusNode.hasFocus) {
        _tooltipController.show();
      } else {
        _tooltipController.hide();
      }
    });
  }

  @override
  void dispose() {
    _textFieldFocusNode.dispose();
    _tooltipController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Tooltip(
      message: errorMsg,
      triggerMode: TooltipTriggerMode.manual, // 设置为手动触发
      controller: _tooltipController,
      child: TextField(
        focusNode: _textFieldFocusNode,
        // 你的TextField原有配置
        decoration: const InputDecoration(
          hintText: "请输入内容",
        ),
      ),
    );
  }
}

方式2:手动使用OverlayEntry(兼容低版本Flutter)

如果你的Flutter版本低于3.10,可通过OverlayEntry手动创建并控制Tooltip样式的弹窗:

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

  @override
  State<YourTextFieldWidget> createState() => _YourTextFieldWidgetState();
}

class _YourTextFieldWidgetState extends State<YourTextFieldWidget> {
  late FocusNode _textFieldFocusNode;
  OverlayEntry? _tooltipOverlay;
  final String errorMsg = record.content[widget.index]['error'];

  @override
  void initState() {
    super.initState();
    _textFieldFocusNode = FocusNode();
    _textFieldFocusNode.addListener(_handleFocusChange);
  }

  void _handleFocusChange() {
    if (_textFieldFocusNode.hasFocus) {
      _showCustomTooltip();
    } else {
      _hideCustomTooltip();
    }
  }

  void _showCustomTooltip() {
    if (_tooltipOverlay != null) return;
    
    // 获取TextField在屏幕上的位置和尺寸
    final renderBox = context.findRenderObject() as RenderBox;
    final globalOffset = renderBox.localToGlobal(Offset.zero);
    final widgetSize = renderBox.size;

    _tooltipOverlay = OverlayEntry(
      builder: (context) => Positioned(
        // 调整位置,让Tooltip显示在TextField上方
        left: globalOffset.dx,
        top: globalOffset.dy - 45,
        child: Material(
          elevation: 4,
          borderRadius: BorderRadius.circular(4),
          color: Colors.grey[800],
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
            child: Text(
              errorMsg,
              style: const TextStyle(color: Colors.white, fontSize: 14),
            ),
          ),
        ),
      ),
    );
    Overlay.of(context).insert(_tooltipOverlay!);
  }

  void _hideCustomTooltip() {
    _tooltipOverlay?.remove();
    _tooltipOverlay = null;
  }

  @override
  void dispose() {
    _textFieldFocusNode.dispose();
    _hideCustomTooltip();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      focusNode: _textFieldFocusNode,
      // 你的TextField原有配置
      decoration: const InputDecoration(
        hintText: "请输入内容",
      ),
    );
  }
}

三、修复长按触发Tooltip的问题

如果需要保留“长按TextField显示Tooltip”的功能,可通过GestureDetector手动转发长按事件给Tooltip,同时不影响TextField的原生长按菜单:

Widget withError(Widget child) {
  final tooltipKey = GlobalKey<TooltipState>();
  return Tooltip(
    key: tooltipKey,
    message: record.content[widget.index]['error'],
    triggerMode: TooltipTriggerMode.manual,
    child: GestureDetector(
      onLongPress: () {
        // 手动触发Tooltip显示
        tooltipKey.currentState?.ensureTooltipVisible();
      },
      // 设置手势穿透,不影响TextField的原生手势
      behavior: HitTestBehavior.translucent,
      child: child,
    ),
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 09:15:08