如何在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
相关产品推荐
相关产品推荐

