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

Flutter如何计算触摸Offset到绘制线段的距离实现选中检测?

Flutter CustomPaint 线段触摸命中判定实现

要实现线条的选中、移动、删除交互,核心是完成触摸点到线段的命中检测,整个判定只需要两步校验,全部通过即判定为命中对应线段。

判定规则

  • 校验触摸点在线段所在直线上的投影,是否落在两个端点构成的线段区间内,排除投影在线段延长线上的误判
  • 计算触摸点到线段的垂直距离,当距离小于预设的命中阈值时,判定为命中。阈值根据交互场景调整:手写笔场景建议设为3-5逻辑像素,手指触摸场景建议设为8-12逻辑像素,适配不同操作的精度要求

可复用判定工具方法

直接在项目中引入以下工具方法即可使用,计算过程全程避免不必要的开根号操作,性能满足大量线条的遍历判定需求:

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

/// 判定触摸点[point]是否命中由[p1]、[p2]两个端点构成的线段
/// [hitTolerance] 为命中允许的最大距离,单位为逻辑像素
bool isPointHitLine(Offset p1, Offset p2, Offset point, {double hitTolerance = 10}) {
  // 线段方向向量
  final double lineX = p2.dx - p1.dx;
  final double lineY = p2.dy - p1.dy;
  // 触摸点到线段起点p1的向量
  final double pointX = point.dx - p1.dx;
  final double pointY = point.dy - p1.dy;

  // 线段长度平方,处理两个端点重合的特殊线段(即点)
  final double lineLengthSq = lineX * lineX + lineY * lineY;
  if (lineLengthSq == 0) {
    return (point - p1).distance <= hitTolerance;
  }

  // 计算投影占线段长度的比例t,t值范围在[0,1]时投影才落在线段有效范围内
  final double t = (pointX * lineX + pointY * lineY) / lineLengthSq;
  final double validT = max(0, min(1, t));

  // 计算线段上离触摸点最近的投影点坐标
  final Offset closestPoint = Offset(
    p1.dx + validT * lineX,
    p1.dy + validT * lineY,
  );

  // 比较触摸点到最近点的距离和命中阈值
  return (point - closestPoint).distance <= hitTolerance;
}

业务层接入方式

注意:命中判定逻辑不需要写在CustomPainter的绘制流程中,只需要在手势回调(如GestureDetector的onTapDown、onPanDown)中执行即可,不会额外增加绘制性能损耗。

在拿到触摸事件的局部坐标后,遍历所有绘制的线条,逐个调用判定方法即可找到当前命中的线条:

// 从手势详情中拿到当前触摸的局部坐标
final Offset touchPosition = event.localPosition;
Line? selectedLine;

for (final shape in shapes) {
  if (shape is Line) {
    if (isPointHitLine(shape.p1!, shape.p2!, touchPosition)) {
      selectedLine = shape;
      break;
    }
  }
}

// 命中线条后即可执行对应的选中、移动、删除业务逻辑
if (selectedLine != null) {
  // 例:标记选中状态、绑定移动偏移更新、从shapes列表移除等
}

如果你需要支持旋转、缩放后的画布命中判定,只需要在传入触摸点和线段端点前,先根据画布的变换矩阵做一次坐标反变换,将触摸点坐标转换到画布的原始坐标系下,再调用上述判定方法即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:09:47