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

如何在Flutter中实现链接Hover时左下角URL提示效果?

Flutter实现鼠标悬停链接时左下角显示URL提示

当然可以实现,Flutter本身没有浏览器那种默认的左下角URL提示,得自己手动构建这个功能,给你两种可行的方案:

方案一:自定义链接Widget(脱离MarkdownBody)

把原来的无状态组件改成有状态组件,通过MouseRegion监听鼠标悬停,用Overlay在屏幕左下角显示URL:

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

class Link extends StatefulWidget {
  const Link({
    super.key,
    required this.urlLabel,
    required this.url,
  });

  final String urlLabel;
  final String url;

  @override
  State<Link> createState() => _LinkState();
}

class _LinkState extends State<Link> {
  OverlayEntry? _urlOverlay;

  Future<void> _launchUrl(String url) async {
    final Uri uri = Uri.parse(url);
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    }
  }

  void _showUrlOverlay() {
    if (_urlOverlay != null) return;
    final overlay = Overlay.of(context);
    _urlOverlay = OverlayEntry(
      builder: (context) => Positioned(
        left: 16, // 左边距,可调整
        bottom: 16, // 底部距,可调整
        child: Material(
          color: Colors.grey.shade800,
          borderRadius: BorderRadius.circular(4),
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            child: Text(
              widget.url,
              style: const TextStyle(color: Colors.white, fontSize: 12),
            ),
          ),
        ),
      ),
    );
    overlay.insert(_urlOverlay!);
  }

  void _hideUrlOverlay() {
    _urlOverlay?.remove();
    _urlOverlay = null;
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onEnter: (_) => _showUrlOverlay(),
      onExit: (_) => _hideUrlOverlay(),
      child: GestureDetector(
        onTap: () => _launchUrl(widget.url),
        child: Text(
          widget.urlLabel,
          style: const TextStyle(
            color: Colors.blue,
            decoration: TextDecoration.underline,
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _hideUrlOverlay(); // 组件销毁时移除Overlay,避免内存泄漏
    super.dispose();
  }
}

方案二:在MarkdownBody中自定义链接样式

如果你想继续使用flutter_markdown的MarkdownBody,可以通过linkBuilder参数替换默认的链接Widget,加入悬停提示逻辑:

import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:url_launcher/url_launcher.dart';

class Link extends StatefulWidget {
  const Link({
    super.key,
    required this.urlLabel,
    required this.url,
  });

  final String urlLabel;
  final String url;

  @override
  State<Link> createState() => _LinkState();
}

class _LinkState extends State<Link> {
  OverlayEntry? _urlOverlay;

  Future<void> _launchUrl(String url) async {
    final Uri uri = Uri.parse(url);
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    }
  }

  void _showUrlOverlay() {
    if (_urlOverlay != null) return;
    final overlay = Overlay.of(context);
    _urlOverlay = OverlayEntry(
      builder: (context) => Positioned(
        left: 16,
        bottom: 16,
        child: Material(
          color: Colors.grey.shade800,
          borderRadius: BorderRadius.circular(4),
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            child: Text(
              widget.url,
              style: const TextStyle(color: Colors.white, fontSize: 12),
            ),
          ),
        ),
      ),
    );
    overlay.insert(_urlOverlay!);
  }

  void _hideUrlOverlay() {
    _urlOverlay?.remove();
    _urlOverlay = null;
  }

  @override
  Widget build(BuildContext context) {
    return MarkdownBody(
      data: '[$widget.urlLabel]($widget.url)',
      linkBuilder: (text, href, title) {
        if (href == null) return Text(text);
        return MouseRegion(
          onEnter: (_) => _showUrlOverlay(),
          onExit: (_) => _hideUrlOverlay(),
          child: GestureDetector(
            onTap: () => _launchUrl(href),
            child: Text(
              text,
              style: const TextStyle(color: Colors.blue, decoration: TextDecoration.underline),
            ),
          ),
        );
      },
    );
  }

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

关键说明

  • MouseRegion:用来监听鼠标的进入和离开事件,触发提示框的显示/隐藏。
  • Overlay:用来在所有Widget之上悬浮显示URL提示,保证提示框不会被其他内容遮挡。
  • 提示框的样式和位置可以根据需求调整(比如背景色、边距、字体大小)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:34:56