简体   繁体   English

将多个可点击的形状添加到UIView

[英]Adding multiple tappable shapes to UIView

I have a floor plan with many exhibitor stands. 我有很多展位的平面图。 When a UIView loads, a UIImage is displayed with the floor plan and a database is checked for a list of exhibitors and their locations. 加载UIView时,将显示UIImage和平面图,并检查数据库以获取参展商及其位置的列表。 The locations are loaded into an array and a UIButton is created for each exhibitor and placed over the floor plan where their stand is. 将位置加载到阵列中,并为每个参展商创建一个UIButton ,并将其放置在其展位所在的平面图上。 When tapped, this button will show information about that exhibitor. 点击时,此按钮将显示有关该参展商的信息。

Here is a screenshot of the floor plan with boxes where the buttons are rendered. 这是平面图的屏幕截图,其中带有渲染按钮的框。

在此处输入图片说明

This works fine as it is BUT I need the buttons to be irregular shapes (triangles, pentagons, circles etc). 这很好用,但是我需要将按钮设置为不规则形状(三角形,五边形,圆形等)。 So I need a way of drawing these shapes and having them clickable in the same way the buttons were. 因此,我需要一种绘制这些形状并使其与按钮一样可单击的方法。

I have created a test class which generates a UIView which contains the shape and added it to my original UIView . 我创建了一个测试类,该类生成一个包含形状的UIView并将其添加到我的原始UIView I get the feeling this may not be the correct way to do this as I will need to have many buttons on the screen and this would mean many views stacked on each other. 我感觉这可能不是正确的方法,因为我将需要在屏幕上具有许多按钮,这意味着许多视图相互堆叠。 I don't know how I could check which shape was tapped as the UIViews would overlap each other. 我不知道如何检查点击的形状,因为UIViews会相互重叠。

Can all the shapes be drawn on one view and then the view added? 是否可以在一个视图上绘制所有形状,然后添加视图? What is the best approach to this? 最好的方法是什么?

In terms of UI the cleanest thing to do is to use actual buttons. 就UI而言,最干净的方法是使用实​​际的按钮。 Set their type to custom, and set their image property to the image you want to display. 将其类型设置为custom,并将其image属性设置为要显示的图像。 That way the buttons handle highlighting correctly, and manage IBActions just like regular buttons. 这样,按钮可以正确处理突出显示,并像常规按钮一样管理IBAction。 You can set all the buttons to point to the same action, and use tag values to figure out which button is which. 您可以将所有按钮设置为指向相同的动作,并使用标签值确定哪个按钮是哪个按钮。

You can create these buttons either from code or in IB - whichever fits your design better. 您可以从代码中或在IB中创建这些按钮-更好地适合您的设计。

You could also do this with custom views or a single view that has drawing on it. 您也可以使用自定义视图或上面带有图形的单个视图来执行此操作。 IF you use views for each booth, you would need to attach a tap gesture recognizer to each view, and set it's userInteractionEnabled flag to YES. 如果对每个展位使用视图,则需要在每个视图上附加一个轻击手势识别器,并将其userInteractionEnabled标志设置为YES。

If you want to use a drawing for the entire floor plan, you would need to add a tap gesture recognizer to the drawing view, and then interpret the coordinates of the tap to figure out which image it lands on. 如果要在整个平面图中使用图形,则需要在图形视图中添加一个轻击手势识别器,然后解释该轻敲的坐标以找出其所放到的图像。

override - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method of your map representer view. 覆盖- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event地图表示者视图的- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event方法的- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event方法。 So you will be able to compare current touch location with all of your shapes, and calculate in which shape your touch point is laying. 因此,您将能够将当前触摸位置与所有形状进行比较,并计算出您的触摸点所处的形状。 There different approach for different shapes (eg is point inside a rectangle? ) 对于不同的形状有不同的方法(例如,点在矩形内吗?

ole has a great project: OBShapedButtons . ole有一个很棒的项目: OBShapedButtons He achieves it by checking the alpha value of the touched pixel and overwriting -pointInside:withEvent: 他通过检查触摸像素的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;
}

Another sample code that test if the point is within a layer mask, maybe you can adapt that more easily: 另一个测试该点是否在图层蒙版中的示例代码,也许您可​​以更轻松地进行调整:

@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

The full article: http://blog.vikingosegundo.de/2013/10/01/hittesting-done-right/ 全文: http : //blog.vikingosegundo.de/2013/10/01/hittesting-done-right/

In the end this is what I did: 最后,这就是我所做的:

  • Looped through all of the stand shapes I needed to have and created a dictionary with UIBezierpath of their coordinates on the floorplan image and the standNo for the shape. 遍历我需要的所有支架形状,并创建一个字典,在平面图图像上使用其坐标的UIBezierpath和形状的standNo。
  • I then added these dictionaries to an array. 然后,我将这些字典添加到数组中。
  • When the screen was tapped I would note the X and Y of the tap position and looped through the array of dictionaries and it checked if the UIBezierpath contained a point made up of the X and Y tapped coordinates. 轻按屏幕时,我会注意轻按位置的X和Y并遍历字典数组,并检查UIBezierpath是否包含由X和Y轻按坐标组成的点。
  • If a shape was found that had the X and Y coordinates within its bounds I would draw a CAShapelayer using the UIBezierpath and adding a fillColor so it showed up on the map. 如果找到一个在其边界内具有X和Y坐标的形状,我将使用UIBezierpath并添加fillColor绘制一个CAShapelayer,使其在地图上显示。 An alertView was then displayed which showed more information about the exhibitor. 然后显示一个alertView,其中显示有关参展商的更多信息。

This method seemed WAY more efficient than actually drawing out hundreds of UIButtons or even CAShaplayers and even with 300+ areas on the floorplan to check through the process appears instant. 这种方法似乎比实际绘制数百个UIButton甚至CAShaplayers,甚至在平面图上具有300多个区域来检查整个过程是否立即显示都更为有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM