非矩形“可点击”区域

时间:2013-02-12 14:07:19

标签: objective-c xcode

我有一张3D地图,里面有许多不同形状的建筑物。我希望用户点击地图上的建筑物,这将充当新视图的segue。

我计划通过创建与建筑物形状相同的隐形按钮,然后将它们放置在图像视图的顶部(用于保存地图)来实现此目的。

在做了一些阅读之后,我发现它并不像我想的那样简单地创建自定义按钮(我认为我将不得不做很多次级和定制,当我有50+以上时这似乎不合理不同形状的按钮,所以我想知道是否有另一种方法我可以用来解决这个问题。


编辑:我现在应该添加所有功能,但是我必须使用默认的矩形按钮,alpha设置为0.1。

2 个答案:

答案 0 :(得分:3)

已编辑改进DATAMODEL

要做到这一点,你将在后台拥有一张带有地图图像的UIView。您可以使用UIImageView或在drawRect中自己渲染图像来完成此操作。

然后,您将定义多个CGPath引用。通过做这样的事情为每个建筑物建造一个...... How to create CGPathRef from Array of points每个建筑物的角落都是点。

现在以某种方式将这些路径存储在数组中。每个“可点击”都需要一条路径 建筑物。

我会将路径存储在Building对象中......

@interface Building : NSObject

@property (nonatomic) CGPath path;

@end

现在在UIView子类中重写- (void)touchesBegan...。然后,您可以获取触摸点并遍历您的路径以找到触摸的那个...

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];

    CGPoint touchPoint = [touch locationInView:self];

    for (Building *building in self.buildings) {
        if (CGPathContainsPoint(building.path, CGAffineTransformIdentity, touchPoint, YES)) {
            //the touch was inside this building!
            //now do something with this knowledge.
        }
    }
}

答案 1 :(得分:1)

我曾经实施过一个meteo应用程序。 我们做了一个地图 - 有几个可点击的区域。 定义这些非矩形区域的最简单方法是将它们定义为UIBezierPath,并使用UITapGestureRecognizer UIBezierPath使用CGPath,但它是纯Objective-C。 在CGPath上的其他优点是,您可以轻松填充/描边这些路径 - 使用随机颜色 - 在调试时可以很好地看到它们

所以

//in you .h, or in class extension

//an array of UIBezierPath you create
// each bezierPath represent an area.
@property (nonatomic, strong) NSArray *myShapes;

//in your .m

- (void)viewDidLoad
{
    [super viewDidLoad];
    //load stuff
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    [self.view addGesture:tap];

    // ...
}

- (void)handleTap:(UITapGestureRecognizer *)tap
{
    UIBezierPath *recognizedArea = nil;
    //if your shapes are defined in self.view coordinates : 
    CGPoint hitPoint = [tap locationInView:self.view];
    for(UIBezierPath *regionPath in self.myShapes){
        if([regionPath containsPoint:tap]){
            recognizedArea = regionPath;
            break;
        }
    }
    //handle touch for THIS specific area when recognizedArea isn't nil
    if(recognizedArea){
        //YOUR CODE HERE
    }
    // you might also iterate with a normal integer increment
    // and use the path index to retrieve region-specific-data from another array

}