gpt4 book ai didi

android - 如何从 Android canvas 获取触摸形状(弧形)?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:57:17 26 4
gpt4 key购买 nike

我正在构建自定义 View 。

它有 4 个弧。

我在 onDraw() 期间使用 RectF 形状绘制圆弧:

// arcPaint is a Paint object initialized
// in the View's constructor
arcPaint.setStrokeWidth(strokeWidth);
arcPaint.setColor(arcColor);

// Draw arcs, arc1, arc2, arc3 & arc4 are
// measured and initialized during onMeasure()
canvas.drawArc(arc1, startAngle, arc1Angle, false, arcPaint);
canvas.drawArc(arc2, startAngle, arc2Angle, false, arcPaint);
canvas.drawArc(arc3, startAngle, arc3Angle, false, arcPaint);
canvas.drawArc(arc4, startAngle, arc4Angle, false, arcPaint);

所以,结果是:

enter image description here

如果我使用 canvas.drawRect() 和这段代码绘制 RectF 对象:

canvas.drawRect(arc1, arcPaint);
canvas.drawRect(arc2, arcPaint);
canvas.drawRect(arc3, arcPaint);
canvas.drawRect(arc4, arcPaint);

结果是这样的:

enter image description here

将所有的圆弧和矩形画在一起,得到:

enter image description here

我知道我可以覆盖 onTouchEvent() 方法并获取 X、Y 坐标,但我不知道每个坐标如何与 Canvas 中绘制的每个形状相关。

我想做的是检测何时在 canvas 中触摸了弧线,而不是矩形,我该如何实现?

编辑:

不是矩形,我的意思是,我不想检测用户何时触摸这些区域(矩形的角):

enter image description here

最佳答案

这基本上归结为比较距该图形中心点的距离。由于边界矩形始终是正方形,因此这些距离之一基本上是固定的,这使得这更容易。

这里的一般方法是计算从中心点到触摸点的距离,并检查该距离与圆弧半径的差值是否在任一笔画宽度的一半以内。

private static boolean isOnRing(MotionEvent event, RectF bounds, float strokeWidth) {
// Figure the distance from center point to touch point.
final float distance = distance(event.getX(), event.getY(),
bounds.centerX(), bounds.centerY());

// Assuming square bounds to figure the radius.
final float radius = bounds.width() / 2f;

// The Paint stroke is centered on the circumference,
// so the tolerance is half its width.
final float halfStrokeWidth = strokeWidth / 2f;

// Compare the difference to the tolerance.
return Math.abs(distance - radius) <= halfStrokeWidth;
}

private static float distance(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}

onTouchEvent() 方法中,isOnRing() 只是通过 MotionEvent 调用,圆弧的边界 RectF,以及 Paint 的笔画宽度。例如:

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isOnRing(event, arc1, arcPaint.getStrokeWidth())) {
// Hit.
}
break;
...
}
...
}

这本身只会确定触摸点是否位于由半径和笔划宽度描述的完整环上的任何位置。也就是说,它不考虑弧中的“间隙”。如果需要,有多种方法可以处理该问题。

如果您打算使起始角和扫描角与 x/y 轴齐平,最简单的方法可能是检查触摸点和中心点坐标差异的标志。从广义上讲,如果 touch x 减去 center x 是正的,那么你在右边;如果为负,则您在左侧。同样,计算顶部或底部将使您能够确定触摸发生在哪个象限,以及是否忽略该事件。

final float dx = event.getX() - arc1.centerX();
final float dy = event.getY() - arc1.centerY();

if (dx > 0) {
// Right side
}
else {
// Left side
}
...

但是,如果任何一个角都不与轴共端点,那么数学就有点复杂了。例如:

private static boolean isInSweep(MotionEvent event, RectF bounds,
float startAngle, float sweepAngle) {
// Figure atan2 angle.
final float at =
(float) Math.toDegrees(Math.atan2(event.getY() - bounds.centerY(),
event.getX() - bounds.centerX()));

// Convert from atan2 to standard angle.
final float angle = (at + 360) % 360;

// Check if in sweep.
return angle >= startAngle && angle <= startAngle + sweepAngle;
}

然后 onTouchEvent() 中的 if 将更改以合并这两个检查。

if (isOnRing(event, arc1, arcPaint.getStrokeWidth()) &&
isInSweep(event, arc1, startAngle, arc1Angle)) {
// Hit.
}

这些方法可以很容易地组合成一个,但为了清楚起见,它们在这里分开。

关于android - 如何从 Android canvas 获取触摸形状(弧形)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44512045/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com