我正在自定义UIView's
中创建多个自定义UIView
。自定义子视图的创建是可以的。它们看起来像这样:
绘制方法非常简单:
[[UIColor brownColor] set];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx,
5.0f);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 0.0f, 0.0f);
CGContextAddLineToPoint(ctx, 100.0f, 0.0);
CGContextAddLineToPoint(ctx, 130.0f, 25.0f);
CGContextAddLineToPoint(ctx, 100.0f, 50.0f);
CGContextAddLineToPoint(ctx, 0.0f, 50.0f);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
[super drawRect:rect];
将它添加到超级视图也很简单:
ITContextFigure *view = [[ITContextFigure alloc] initWithFrame:CGRectMake(location.x, location.y, 135.0f, 50.0f)];
[view setBackgroundColor:[UIColor yellowColor]];
[self addSubview:view];
所以我的问题是:
1)如何检测何时与另一个重叠?
我看到了这个解决方案:
if (CGRectContainsRect([myImageView1 frame], [myImageView2 frame])) {
NSLog(@"Overlaped, it's working!");
}
但如果我有多个UIViews
,在for
上执行super view
并检查每个子视图对我来说似乎不是一个好方法。
2)在这种情况下,可以做些什么?
我的主要目标是检测何时发生这种情况:
更新1.0
去尝试所展示的here,因为没有更优雅的方式。如果我能够实现它,我会在Github上发布代码,如果有人需要的话。
答案 0 :(得分:3)
您可以通过巧妙地对数据进行排序(这些称为扫描线或渗透线算法)来显着减少您需要进行的碰撞检测次数。以下是如何将此技术应用于您的情况的概述。
将您的子视图排序为按升序y排序的数组。如果两个子视图共享相同的y,则按升序x对它们进行排序。这是您的非活动列表,这构成了算法的主要输入。
算法如下:
虽然有非活动子视图,但请选择active_y
。这是非活动列表中第一个子视图的y坐标。
将所有带active_y
行的原点的子视图移至工作列表,按升序x排序。这是活动列表。
运行活动列表冲突测试每个子视图以及列表中的后续子视图。你可以在列表中使用两个索引(我们称之为left
和right
)。只要您看到right
子视图无法与left
相交,您就可以推进left
索引。
在进行碰撞检测时,您还要检查子视图现在是否完全低于active_y
。一旦完成,您应该将其从活动列表中删除。
当非活动列表上的所有子视图都已被使用并且最终通过活动列表运行完成时,算法就会完成。
该算法大大减少了您需要执行的碰撞检测次数,大致为O(n log n),但它也可以简化碰撞检测本身。
由于活动列表从左到右排序,因此您始终知道何时执行检测例程,哪一个在左侧,哪个在右侧。因此,例如,在比较示例中的箭头形状时,您只需要检查右侧形状的两个最左侧顶点是否落在左侧形状内。您可能会发现CGPathContainsPoint
有用。
如果您正在处理的不同形状的数量增加,那么您可能需要考虑将碰撞检测推入扫描线算法本身。这有点棘手,但基本上不是包含子视图指针的列表,而是包含构成形状的线段(不包括水平形状)。