向UIView添加多个可插拔形状

时间:2014-03-03 12:21:24

标签: ios objective-c cocoa-touch uibezierpath

我有很多参展商的平面图。加载UIView时,会显示UIImage平面图,并检查数据库中是否有参展商及其位置列表。这些位置被加载到一个阵列中,并为每个参展商创建UIButton,并将其放置在他们的展位所在的平面图上。点击时,此按钮将显示有关该参展商的信息。

以下是平面图的屏幕截图,其中包含用于呈现按钮的框。

enter image description here

这很好,因为它是我需要按钮是不规则的形状(三角形,五边形,圆形等)。因此,我需要一种绘制这些形状的方法,并按照按钮的方式单击它们。

我创建了一个测试类,它生成一个UIView,其中包含形状并将其添加到原始UIView。我觉得这可能不是正确的方法,因为我需要在屏幕上有许多按钮,这意味着许多视图堆叠在一起。我不知道如何检查哪个形状被点击,因为UIViews会相互重叠。

可以在一个视图上绘制所有形状,然后添加视图吗?最好的办法是什么?

4 个答案:

答案 0 :(得分:0)

在UI方面,最干净的事情是使用实际按钮。将其类型设置为自定义,并将其图像属性设置为要显示的图像。这样,按钮正确处理突出显示,并像常规按钮一样管理IBActions。您可以将所有按钮设置为指向相同的操作,并使用标记值来确定哪个按钮是哪个。

您可以通过代码或IB创建这些按钮 - 无论哪种更适合您的设计。

您也可以使用自定义视图或在其上绘制的单个视图执行此操作。如果您为每个展位使用视图,则需要为每个视图附加一个轻击手势识别器,并将其userInteractionEnabled标志设置为YES。

如果要对整个平面图使用绘图,则需要在绘图视图中添加点击手势识别器,然后解释点击的坐标以确定它所在的图像。

答案 1 :(得分:0)

倍率 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 地图代表视图的方法。因此,您将能够将当前触摸位置与所有形状进行比较,并计算接触点所处的形状。对于不同的形状有不同的方法(例如is point inside a rectangle?

答案 2 :(得分:0)

ole有一个很棒的项目:OBShapedButtons。他通过检查触摸的像素的alpha值并覆盖-pointInside:withEvent:

来实现它
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{
    // Return NO if even super returns NO (i.e., if point lies outside our bounds)
    BOOL superResult = [super pointInside:point withEvent:event];
    if (!superResult) {
        return superResult;
    }

    // Don't check again if we just queried the same point
    // (because pointInside:withEvent: gets often called multiple times)
    if (CGPointEqualToPoint(point, self.previousTouchPoint)) {
        return self.previousTouchHitTestResponse;
    } else {
        self.previousTouchPoint = point;
    }

    BOOL response = NO;

    if (self.buttonImage == nil && self.buttonBackground == nil) {
        response = YES;
    }
    else if (self.buttonImage != nil && self.buttonBackground == nil) {
        response = [self isAlphaVisibleAtPoint:point forImage:self.buttonImage];
    }
    else if (self.buttonImage == nil && self.buttonBackground != nil) {
        response = [self isAlphaVisibleAtPoint:point forImage:self.buttonBackground];
    }
    else {
        if ([self isAlphaVisibleAtPoint:point forImage:self.buttonImage]) {
            response = YES;
        } else {
            response = [self isAlphaVisibleAtPoint:point forImage:self.buttonBackground];
        }
    }

    self.previousTouchHitTestResponse = response;
    return response;
}

另一个测试点是否在图层蒙版内的示例代码,也许您可​​以更轻松地进行调整:

@implementation MyView
//
// ...
//
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    CGPoint p = [self convertPoint:point toView:[self superview]];
    if(self.layer.mask){
        if (CGPathContainsPoint([(CAShapeLayer *)self.layer.mask path], NULL, p, YES) )
            return YES;
    }else {
        if(CGRectContainsPoint(self.layer.frame, p))
            return YES;
    }
    return NO;
}

@end

完整文章:http://blog.vikingosegundo.de/2013/10/01/hittesting-done-right/

答案 3 :(得分:0)

最后这就是我所做的:

  • 循环浏览我需要拥有的所有立场形状,并在平面图图像上创建一个带有UIBezierpath字典的字典,并为该形状创建standNo。
  • 然后我将这些词典添加到数组中。
  • 当点击屏幕时,我会注意点击位置的X和Y并循环遍历字典数组,并检查UIBezier路径是否包含由X和Y点击坐标组成的点。
  • 如果找到一个在其边界内有X和Y坐标的形状,我会使用UIBezier路径绘制一个CAShapelayer并添加一个fillColor,以便它显示在地图上。然后显示alertView,显示有关参展商的更多信息。

这种方法似乎比实际绘制数百个UIButton甚至CAS播放器更有效率,甚至在平面图上有300多个区域来检查整个过程是否即时。