【问题标题】:How do I make a MKAnnotationView touch sensitive?如何使 MKAnnotationView 触摸敏感?
【发布时间】:2011-12-27 19:04:24
【问题描述】:

我目前有一个带有一些注释的地图视图。我有自定义图像的注释。我要解决的问题是图像的敏感性。当我试图拖动它们时,感觉就像我必须触摸确切的中心才能使其聚焦。有没有办法让触摸范围更大?

【问题讨论】:

    标签: ios iphone objective-c cocoa-touch


    【解决方案1】:

    为此,您需要继承MKAnnotationView 以创建您自己的自定义MKAnnotationView。在您的子类中,覆盖以下函数:

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
    {
        // Return YES if the point is inside an area you want to be touchable
    }
    
    - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
    {
        // Return the deepest view that the point is inside of.
    }
    

    这允许按下交互式视图(例如按钮等)。 MKAnnotationView 中的默认实现对 pointInsidehitTest 并不严格,因为它允许将实际位于一个注释内的按下发送到另一个注释。它通过找出离接触点最近的注释中心并将事件发送到该注释来做到这一点,这样靠近(重叠)的注释就不会相互阻止被选中。但是,在您的情况下,如果用户要选择并拖动最顶部的注释,您可能希望阻止其他注释,因此上述方法可能是您想要的,否则它会将您设置在正确的路径上。

    编辑: 我在 cmets 中被问到hitTest:withEvent: 的示例实现 - 这完全取决于您要实现的目标。最初的问题建议在注释中触摸和拖动图像,而在我的情况下,我在注释中有一些我想要交互的按钮。这是我的代码:

    - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
    {
        UIView* hitView = [super hitTest:point withEvent:event];
        if (hitView != nil)
        {
            // ensure that the callout appears above all other views
            [self.superview bringSubviewToFront:self];
    
            // we tapped inside the callout
            if (CGRectContainsPoint(self.resultView.callButton.frame, point))
            {
                hitView = self.resultView.callButton;
            }
            else if (CGRectContainsPoint(self.resultView.addButton.frame, point))
            {
                hitView = self.resultView.addButton;
            }
            else
            {
                hitView = self.resultView.viewDetailsButton;
            }
            [self preventSelectionChange];
        }
        return hitView;
    }
    

    如您所见,它非常简单 - MKAnnotationView 实现(在我的实现的第一行称为 super)仅返回第一个(最外层)视图,它不会深入查看视图层次结构触摸实际上在哪个子视图中。就我而言,我只是检查触摸是否在三个按钮之一内并返回。在其他情况下,您可能会在层次结构中进行简单的基于矩形的向下钻取或更复杂的命中测试,例如避免视图中的透明区域以允许触摸通过这些部分。如果您确实需要向下钻取,CGRectContainsPoint 可以像我使用它一样使用,但请记住将您的点偏移到您钻取的每个视图级别的本地视图坐标中。

    preventSelectionChange 方法是为了防止我的自定义注释被选中,我将它用作地图图钉的可自定义/交互式标注,这会保持与它相关的图钉被选中,而不是允许选择更改为此注释.

    【讨论】:

    • 你能实现 hitTest 方法吗?
    • 如果我能再次投票给你的答案,我会的!感谢您的更新。
    • 你好,pointInside:withEvent: 怎么样?这是您建议实施 CGRectContainsPoint 的地方吗?
    • @Daniel 是的,如果您愿意,您可以对这两种方法使用相同的实现,以确定该点是否应被视为“在”您的注释中。但是,pointInside:withEvent 可能要简单得多,如果该点位于最外面的视图矩形内,则返回 YES。唯一需要返回 NO 的情况是当您有透明区域应该被视为“在您的视图之外”时,即使它们位于边界矩形内。
    • 我可以在我的按钮上接收触摸事件,但内部触摸不会触发,地图视图似乎捕获了这一点并处理取消选择注释。有什么想法吗?
    【解决方案2】:

    您是继承了 MKAnnotationView 还是更改了它的刚刚设置的图像属性?

    这是设置图像属性的文档。

    讨论: 将新图像分配给此属性还会更改视图框架的大小,使其与新图像的宽度和高度相匹配。视图框架的位置不会改变。

    检查注释视图的框架大小,这是您的对象可以接收触摸的位置。

    【讨论】:

      【解决方案3】:

      我通过以下方式实现了类似的东西

      1. 创建处理触摸的手势识别器类的子类
      2. 创建 UIImage 类的子类,该类使用识别器类来处理您的手势
      3. 在注释中使用它

      如果您在图像中的任何位置执行手势,手势识别器子类将处理您的手势。这应该可以帮助你。

      让我们了解此解决方案是否对您有用...

      【讨论】:

        【解决方案4】:

        @jhabbott 解决方案从未对我有用,正如我提到的 here

        我有一个图像和一个标签并排。通过设置 annotationview image 属性显示图像,并通过添加 UILabel 来显示标签

        我将func point(inside:with:) 方法重定向到UILabel 方法(包括图像区域),hitTest 确实返回了完全相同的视图,无论我单击标签还是图像。但是标签点击并没有产生任何回调...

        最后,我扩大了 MKAnnotationView 框架以包含标签 + 图像,我将 annotationView.image 设置为 nil,并创建了我的自定义 UIImageView

        因为我想要图像中间的锚点,所以我必须设置一个自定义的:

        self.frame = CGRect(x: 0, y: 0, width: 
        self.myLabel.frame.width, height: self.myLabel.frame.height)
        self.centerOffset = CGPoint(x: self.frame.width/2, y: self.myImageView.frame.height/2)
        

        然后我删除了 point(inside:with:)hitTest(point:with:) 覆盖什么都没做的事情。

        现在,我的注释视图第一次完全反应。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-20
          相关资源
          最近更新 更多