Android:如何检查矩形是不是包含触摸点?
Posted
技术标签:
【中文标题】Android:如何检查矩形是不是包含触摸点?【英文标题】:Android: How to check if a rectangle contains touched point?Android:如何检查矩形是否包含触摸点? 【发布时间】:2012-03-24 04:27:03 【问题描述】:我会尝试开发一个可以绘制平面图的应用程序。因此,每个房间都有自己的 ID 或 name,如果我触摸一个房间,我想显示带有该 ID 或名称的 Toast 消息。问题是如何检查是否以及哪个路径被触摸!
我看到很多关于这个问题的话题讨论。有人说要使用getBounds
方法,然后包含检查触摸点是否在Rect 中的方法。但是,我猜getBounds
返回包含路径的最小Rect
,对吧?
因此,房间有不同的自定义几何形状,因此,如果我得到大约 2 个关闭房间的边界,方法可以返回一组共享的点。坏的!每个房间只有他们的面积分数。我该如何解决这个问题?
在 ios 中我可以使用 PathContainsPoint
方法,但不幸的是,android Path 没有类似的东西。
【问题讨论】:
【参考方案1】:通过路径并检查路径上的位置是否靠近触摸点。以下方法适用于线性路径和复杂路径。
fun Path.doIntersect(x: Float, y: Float, width: Float): Boolean
val measure = PathMeasure(this, false)
val length = measure.length
val delta = width / 2f
val position = floatArrayOf(0f, 0f)
val bounds = RectF()
var distance = 0f
var intersects = false
while (distance <= length)
measure.getPosTan(distance, position, null)
bounds.set(
position[0] - delta,
position[1] - delta,
position[0] + delta,
position[1] + delta
)
if (bounds.contains(x, y))
intersects = true
break
distance += delta / 2f
return intersects
【讨论】:
【参考方案2】:正如 Edward Falk 所说,最好的方法是使用 path.op(),因为 Region 是正方形的。一个点可以在 2 或 3 个区域中。
例如:
所有区域都会包含蓝点,但实际上只有 path4 包含这个点。
int x, y;
Path tempPath = new Path(); // Create temp Path
tempPath.moveTo(x,y); // Move cursor to point
RectF rectangle = new RectF(x-1, y-1, x+1, y+1); // create rectangle with size 2xp
tempPath.addRect(rectangle, Path.Direction.CW); // add rect to temp path
tempPath.op(pathToDetect, Path.Op.DIFFERENCE); // get difference with our PathToCheck
if (tempPath.isEmpty()) // if out path cover temp path we get empty path in result
Log.d(TAG, "Path contains this point");
return true;
else
Log.d(TAG, "Path don't contains this point");
return false;
【讨论】:
【参考方案3】:Region 和 path.op() 方法运行良好,但缺乏精确度。经过一些测试,他们似乎在路径的段级别定义了一个区域,如下所示:image segment zone。另一种方法是使用polygons。虽然提供了更好的结果,但它仍然记录了一些意想不到的触摸,并错过了明显的触摸。但是还有另一种解决方案,它包括沿路径检索一组点,并在它们周围的区域内记录触摸。为此,我们可以使用PathMeasure
类来获取所需的点数,并将它们存储在List<Float>
中:
PathMeasure pathMeasure = new PathMeasure(path, false);
List<Float> listFloat = new ArrayList<>();
for (float i = 0; i < 1.1; i += 0.1)
float[] pointCoordinates = new float[2];
pathMeasure.getPosTan(pathMeasure.getLength() * i, pointCoordinates, null);
listFloat.add(pointCoordinates[0]);
listFloat.add(pointCoordinates[1]);
然后,我们需要遍历List<Float>
并检查触摸事件是否在围绕这些点的定义区域内。在这里,一个区域覆盖了路径长度的十分之一,因为我们收集了十个点:
float areaLength = pathMeasure.getLength() / 20; // since we collect ten points, we define a zone covering a tenth of path length
for (int i = 0; i < listFloat.size() - 1; i += 2)
if (touchX > listFloat.get(i) - areaLength
&& touchX < listFloat.get(i) + areaLength
&& touchY > listFloat.get(i+1) - areaLength
&& touchY < listFloat.get(i+1) + areaLength)
Log.d(TAG, "path touched");
这些连续的区域以更高的精度捕获触摸事件,更接近路径:image points zone。
可以改进此方法,通过使用Rect
类来确保这些区域不相互重叠,并以更好的精度限制起点和终点。
【讨论】:
【参考方案4】:这里有一个想法:创建一个新路径,它是围绕被触摸点的一个小正方形,然后使用 path.op() 将该路径与要测试的路径相交,看看结果是否为空。
【讨论】:
是的,但您仅限于 API 19 及更高版本。还有其他解决办法吗? 谢谢,我已经通过继承 Path 并跟踪所有点来解决它,然后我使用了这个 ***.com/a/16391873/3284364 公式并将其重写为 Java。 我想如果您愿意,我可以发布带有完整解决方案的答案。不知道这是否会帮助任何人 这个答案不起作用。也许这是预期的行为,也许是一个错误。我使用Path.op(__, Path.Op.INTERSECT)
来查看路径是否与以 (x, y) 为中心的小矩形相交,并且当 (x,y) 相对靠近路径但不在路径内部时,它有时会返回非空交叉点。注意我的路径是由直线组成的,有时它们会自行进入。另请注意,这不仅仅是因为我为op()
创建的“小矩形”不够小!
@Bartando 我对您的解决方案很感兴趣,您可以发布答案吗?【参考方案5】:
好的,我解决了我的问题。我发布示例代码:
Path p;
Region r;
@Override
public void onDraw(Canvas canvas)
p = new Path();
p.moveTo(50, 50);
p.lineTo(100, 50);
p.lineTo(100, 100);
p.lineTo(80, 100);
p.close();
canvas.drawPath(p, paint);
RectF rectF = new RectF();
p.computeBounds(rectF, true);
r = new Region();
r.setPath(p, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
public boolean onTouch(View view, MotionEvent event)
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
Log.d(TAG, "point: " + point);
if(r.contains((int)point.x,(int) point.y))
Log.d(TAG, "Touch IN");
else
Log.d(TAG, "Touch OUT");
return true;
【讨论】:
这会在路径周围而不是折线上的给定边界多边形中识别触摸事件。 正是我想要的 这不重要。我为我的目的保存了每个接触点 仅供参考,在 onDraw 中创建新的 RectF 和 Region 对性能不利,如果可能的话更好地重用。 我有另一条路径而不是事件 (x,y) 那么我如何检查我的一条路径是否在当前路径内?以上是关于Android:如何检查矩形是不是包含触摸点?的主要内容,如果未能解决你的问题,请参考以下文章