【问题标题】:Gestures to subviews & MKMapView in iOS - basic iOSiOS 中子视图和 MKMapView 的手势 - 基本 iOS
【发布时间】:2013-02-08 23:11:21
【问题描述】:

我有以下设置:

 mainViewController
    OverlayView - UIView
    mapView - MKMapView

我的 OverlayView 显示在 mapView 上并响应 UIPanGestureRecognizer

现在因为 OverlayView 在 MapView 之上,我无法让 MapView 的缩放功能发挥作用..

我必须做些什么才能让 mapView 对捏合做出反应并让 OverLayView 对 Pan 做出反应(就像现在一样)?

我现在的解决方案是在 mainViewController 中实现 pinch2zoom 功能,以便它相应地缩放 mapView,但它不如最初的 Apple 实现那么流畅。

【问题讨论】:

    标签: ios objective-c uiview mkmapview subview


    【解决方案1】:

    如果您有一个视图应该在 MKMapView 前面,并且随着地图在其下方移动而不在屏幕上移动,您应该按照您的描述实现它,作为前面的单独视图(即在顶部)地图视图。但是,与其让这个前视图处理手势并尝试以编程方式更改地图视图,不如将这个前视图的userInteractionEnabled 设置为NO(您可以通过编程方式或通过Interface Builder 执行此操作)。这将让它后面的地图视图接收到触摸。

    如果您在该前视图上有一些需要接受用户交互的控件,则继续为这几个控件启用用户交互,但请确保该前视图的大部分配置为没有userInteractionEnabled


    如果您想要一个应随地图移动的叠加层,您只需将叠加层添加到MKMapView 本身,而不是单独的视图。请参阅位置感知编程指南中的Displaying Overlays on a Map如果您使用MKMapView 覆盖而不是单独的视图,则不会丢失任何内置手势。

    例如,如果您将MKMapViewdelegate 设置为您的视图控制器,那么您可以在iOS 7 中编写rendererForOverlay(或早期版本的viewForOverlay 方法):

    // for iOS7+; see `viewForOverlay` for earlier versions
    
    - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[MKPolygon class]])
        {
            MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];
    
            renderer.fillColor   = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            renderer.lineWidth   = 3;
    
            return renderer;
        }
    
        if ([overlay isKindOfClass:[MKCircle class]])
        {
            MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:overlay];
    
            renderer.fillColor   = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            renderer.lineWidth   = 3;
    
            return renderer;
        }
    
        if ([overlay isKindOfClass:[MKPolyline class]])
        {
            MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
    
            renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            renderer.lineWidth   = 3;
    
            return renderer;
        }
    
        return nil;
    }
    
    // for iOS versions prior to 7; see `rendererForOverlay` for iOS7 and later
    
    - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[MKPolygon class]])
        {
            MKPolygonView *overlayView = [[MKPolygonView alloc] initWithPolygon:overlay];
    
            overlayView.fillColor      = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            overlayView.strokeColor    = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            overlayView.lineWidth      = 3;
    
            return overlayView;
        }
    
        if ([overlay isKindOfClass:[MKCircle class]])
        {
            MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:overlay];
    
            overlayView.fillColor     = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            overlayView.strokeColor   = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            overlayView.lineWidth     = 3;
    
            return overlayView;
        }
    
        if ([overlay isKindOfClass:[MKPolyline class]])
        {
            MKPolylineView *overlayView = [[MKPolylineView alloc] initWithPolyline:overlay];
    
            overlayView.strokeColor     = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            overlayView.lineWidth       = 3;
    
            return overlayView;
        }
    
        return nil;
    }
    

    这处理多边形、圆和线。显然,例如,如果您只绘制多边形,则可以相应地简化上述代码。

    完成此操作后,您现在可以直接向地图添加叠加层。例如,这会添加一个覆盖,它是围绕特定坐标的特定大小的矩形:

    - (void)addOverlayAround:(CLLocationCoordinate2D)originalCoordinate atDistance:(double)distanceKm
    {
        MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(originalCoordinate, distanceKm * 1000.0 * 2.0, distanceKm * 1000 * 2.0);
        MKCoordinateSpan span = region.span;
    
        CLLocationCoordinate2D  points[4];
        points[0] = CLLocationCoordinate2DMake(originalCoordinate.latitude  + span.latitudeDelta / 2.0,
                                               originalCoordinate.longitude - span.longitudeDelta / 2.0);
        points[1] = CLLocationCoordinate2DMake(originalCoordinate.latitude  + span.latitudeDelta / 2.0 ,
                                               originalCoordinate.longitude + span.longitudeDelta / 2.0);
        points[2] = CLLocationCoordinate2DMake(originalCoordinate.latitude  - span.latitudeDelta / 2.0,
                                               originalCoordinate.longitude + span.longitudeDelta / 2.0);
        points[3] = CLLocationCoordinate2DMake(originalCoordinate.latitude  - span.latitudeDelta / 2.0,
                                               originalCoordinate.longitude - span.longitudeDelta / 2.0);
    
        MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4];
        if ([self.mapView respondsToSelector:@selector(addOverlay:level:)])
            [self.mapView addOverlay:poly level:MKOverlayLevelAboveLabels];
        else
            [self.mapView addOverlay:poly];
    
    //    // If you want to draw a circle around the coordinate, instead, you could do something like:
    //
    //    MKCircle *circle = [MKCircle circleWithCenterCoordinate:originalCoordinate radius:distanceKm * 1000.0 * sqrt(2.0)];
    //    if ([self.mapView respondsToSelector:@selector(addOverlay:level:)])
    //        [self.mapView addOverlay:circle level:MKOverlayLevelAboveLabels];
    //    else
    //        [self.mapView addOverlay:circle];
    
    //    // if you want to draw some lines, you could do something like:
    //  
    //    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:points count:4];
    //    if ([self.mapView respondsToSelector:@selector(addOverlay:level:)])
    //        [self.mapView addOverlay:polyline level:MKOverlayLevelAboveLabels];
    //    else
    //        [self.mapView addOverlay:polyline];
    
        self.mapView.delegate = self;
    }
    

    【讨论】:

    • 谢谢!虽然我需要叠加来使用用户触摸进行动画处理(就像用户控制的指南针一样)并且我不知道如何使用 MKPolygonView 进行动画处理,所以我选择了自定义 UIView .. 在我的情况下,叠加层几乎是位置- 独立的(就像各种 GUI)..
    • @Stpn 啊,这要容易得多。如果您只是将userInteractionEnabled 设置为NO,它将让用户交互传递到地图视图。确保将其设置为 NO,作为您放置在地图顶部的视图的背景。
    【解决方案2】:

    我现在实际上不知道我要提出的建议是否可行,或者是否是一个好的解决方案,无论如何这就是想法

    将您的 MainViewController 设置为手势识别器的委托

    -(BOOL)gestureRecognizer:(UIGestureRecognizer*)gr shouldReceiveTouch:(UITouch*)touch{
        if([gr isKindOfClass:[UIPanGestureRecognizer class]])
            [mapView setUserInteractionEnabled:NO];
        else if([gr isKindOfClass:[UIPinchGestureRecognizer class]])
            [overlayView setUserInteractionEnabled:YES];
        return YES;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-22
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多