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

Flutter如何实现含图片、图标等自定义内容的Tooltip提示框

Flutter自定义富内容悬停提示实现方案

Flutter 内置 Tooltip 组件仅支持纯文本提示,要实现嵌入图片、图标等任意自定义Widget的悬停提示效果,无需引入第三方依赖,通过内置组件组合即可完成,完美适配桌面端交互逻辑。

可复用组件实现

核心通过MouseRegion监听鼠标悬停/移出事件,借助Overlay插入自定义浮层,自动处理位置偏移、屏幕边界适配、资源回收逻辑,封装后的组件调用方式和你预期的写法完全一致。

首先封装通用CustomTooltip组件:

import 'package:flutter/material.dart';

class CustomTooltip extends StatefulWidget {
  final Widget child;
  final Widget tooltipContent;
  final double verticalOffset;
  final Duration waitDuration;

  const CustomTooltip({
    super.key,
    required this.child,
    required this.tooltipContent,
    this.verticalOffset = 15,
    this.waitDuration = const Duration(milliseconds: 200),
  });

  @override
  State<CustomTooltip> createState() => _CustomTooltipState();
}

class _CustomTooltipState extends State<CustomTooltip> {
  OverlayEntry? _overlayEntry;
  bool _isTooltipShowing = false;

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

  void _showTooltip() {
    if (_isTooltipShowing) return;
    final renderBox = context.findRenderObject() as RenderBox;
    final targetSize = renderBox.size;
    final targetOffset = renderBox.localToGlobal(Offset.zero);
    final overlay = Overlay.of(context);
    final screenSize = MediaQuery.of(context).size;

    _overlayEntry = OverlayEntry(
      builder: (context) {
        // 默认显示在目标组件下方
        double left = targetOffset.dx;
        double top = targetOffset.dy + targetSize.height + widget.verticalOffset;
        const defaultTooltipWidth = 200.0;
        const defaultTooltipHeight = 150.0;
        
        // 右侧超出屏幕则右对齐目标组件
        if (left + defaultTooltipWidth > screenSize.width) {
          left = targetOffset.dx + targetSize.width - defaultTooltipWidth;
        }
        // 下方空间不足则切换到目标组件上方显示
        if (top + defaultTooltipHeight > screenSize.height) {
          top = targetOffset.dy - defaultTooltipHeight - widget.verticalOffset;
        }

        return Positioned(
          left: left,
          top: top,
          child: Material(
            color: Colors.transparent,
            elevation: 8,
            borderRadius: BorderRadius.circular(10),
            child: widget.tooltipContent,
          ),
        );
      },
    );

    overlay.insert(_overlayEntry!);
    _isTooltipShowing = true;
  }

  void _removeTooltip() {
    _overlayEntry?.remove();
    _overlayEntry = null;
    _isTooltipShowing = false;
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onEnter: (_) {
        Future.delayed(widget.waitDuration, () {
          if (mounted && !_isTooltipShowing) _showTooltip();
        });
      },
      onExit: (_) => _removeTooltip(),
      child: widget.child,
    );
  }
}

调用示例

封装完成后可以直接按照你预期的方式使用,提示内容支持传入任意Widget:

Widget build(BuildContext context) {
  return Center(
    child: CustomTooltip(
      // 自定义提示内容,图片、图标、按钮、复杂布局均可传入
      tooltipContent: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(10),
          color: Colors.grey[800],
        ),
        child: Column(
          children: [
            const SizedBox(height: 10),
            const Text(
              'This is a tooltip',
              style: TextStyle(
                fontSize: 14,
                color: Colors.white,
              ),
            ),
            const SizedBox(height: 10),
            const Icon(Icons.thumb_up_alt, color: Colors.white),
          ],
        ),
      ),
      child: Image.asset(
        'assets/image.png',
        height: 300,
        width: 300,
      ),
    ),
  );
}

扩展说明

  • 组件自带悬停延迟触发逻辑,和系统原生Tooltip交互体验一致,避免鼠标快速划过时无效弹出
  • 自动适配屏幕边界,不会出现提示框超出屏幕显示不全的问题
  • 组件销毁时自动清理浮层资源,无内存泄漏风险
  • 可根据游戏UI风格自行修改阴影、圆角、偏移量、触发延迟等参数
  • 如果需要支持提示框内点击、鼠标悬停在提示框上不消失的效果,只需在浮层外层嵌套MouseRegion调整移除逻辑即可,扩展成本极低
  • 如果提示内容为动态尺寸,可在浮层渲染完成后通过RenderBox获取内容实际尺寸,动态调整位置偏移即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:36:15