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

Flutter中如何判断鼠标从Widget的哪一侧离开?

Flutter中判断鼠标从Widget哪一侧离开的实现方式

当然有简便的实现方式,核心思路是在鼠标离开时,获取其相对于目标Widget的本地坐标,再结合Widget的尺寸边界,计算鼠标位置到各边的距离,距离最短的一侧就是离开方向。

具体实现代码

可以封装一个可复用的DirectionalMouseRegion组件,内部通过MouseRegion监听事件并处理方向判断:

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

class DirectionalMouseRegion extends StatefulWidget {
  final Widget child;
  final void Function(String direction) onExitDirection;

  const DirectionalMouseRegion({
    super.key,
    required this.child,
    required this.onExitDirection,
  });

  @override
  State<DirectionalMouseRegion> createState() => _DirectionalMouseRegionState();
}

class _DirectionalMouseRegionState extends State<DirectionalMouseRegion> {
  RenderBox? _renderBox;

  @override
  void initState() {
    super.initState();
    // 等待Widget渲染完成后获取RenderBox
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _renderBox = context.findRenderObject() as RenderBox;
    });
  }

  String _getExitDirection(PointerExitEvent event) {
    if (_renderBox == null) return 'unknown';
    
    final localPosition = _renderBox!.globalToLocal(event.position);
    final size = _renderBox!.size;

    // 计算鼠标位置到Widget各边的距离
    final distanceToLeft = localPosition.dx;
    final distanceToRight = size.width - localPosition.dx;
    final distanceToTop = localPosition.dy;
    final distanceToBottom = size.height - localPosition.dy;

    // 找出距离最短的边
    final minDistance = [distanceToLeft, distanceToRight, distanceToTop, distanceToBottom].reduce((a, b) => a < b ? a : b);

    if (minDistance == distanceToLeft) return 'left';
    if (minDistance == distanceToRight) return 'right';
    if (minDistance == distanceToTop) return 'top';
    return 'bottom';
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onExit: (event) {
        final direction = _getExitDirection(event);
        widget.onExitDirection(direction);
      },
      child: widget.child,
    );
  }
}

使用示例

直接将需要监听的Widget作为子组件传入,即可获取离开方向:

DirectionalMouseRegion(
  onExitDirection: (direction) {
    print('鼠标从$direction侧离开');
  },
  child: Container(
    width: 200,
    height: 200,
    color: Colors.lightBlueAccent,
    alignment: Alignment.center,
    child: const Text('Hover me'),
  ),
)

注意事项

  1. 必须等待Widget渲染完成后才能获取RenderBox,否则无法正确计算坐标和尺寸,这里用addPostFrameCallback确保时机正确。
  2. 如果Widget尺寸会动态变化(比如响应式布局),可以在didUpdateWidget或添加SizeChangedLayoutNotifier来更新_renderBox的引用,保证判断准确。
  3. 这种基于距离判断的方式逻辑简单,适用于绝大多数常规场景,不需要依赖额外第三方库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:48:28