2010-11-07 5 views
9

Ich versuche, ein MKMapView als MKOverlayView ein benutzerdefiniertes Bild hinzufügen - Ich muss Benutzer von Scrollen außerhalb der Grenzen des Overlays beschränken. Gibt es dafür vorhandene Funktionen? Oder irgendwelche anderen Vorschläge?Beschränken MKMapView scrollen

Danke, Matt

Antwort

18

Wenn Sie nur die Karte Blick auf die Overlay einfrieren möchten, können Sie den angezeigten Kartenausschnitt der Region auf die Grenzen des Overlays festgelegt und eingestellt scrollEnabled und zoomEnabled-NO.

Aber das lässt den Benutzer nicht innerhalb der Grenzen des Overlays scrollen oder zoomen.

Es gibt keine integrierten Möglichkeiten, die Kartenansicht auf die Grenzen des Overlays zu beschränken. Sie müssten dies also manuell tun. Stellen Sie zunächst sicher, dass Ihr Objekt MKOverlay die Eigenschaft boundingMapRect implementiert. Dies kann dann in der Delegatenmethode regionDidChangeAnimated verwendet werden, um die Ansicht nach Bedarf manuell anzupassen.

Hier ist ein Beispiel, wie dies getan werden könnte.
Code unten sollte in der Klasse sein, die die MKMapView hat.
Stellen Sie sicher, dass die Kartenansicht anfänglich auf eine Region eingestellt ist, in der das Overlay sichtbar ist.

//add two ivars to the .h... 
MKMapRect lastGoodMapRect; 
BOOL manuallyChangingMapRect; 

//in the .m... 
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated 
{ 
    if (manuallyChangingMapRect) 
     return;  
    lastGoodMapRect = mapView.visibleMapRect; 
} 

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated 
{ 
    if (manuallyChangingMapRect) //prevents possible infinite recursion when we call setVisibleMapRect below 
     return;  

    // "theOverlay" below is a reference to your MKOverlay object. 
    // It could be an ivar or obtained from mapView.overlays array. 

    BOOL mapContainsOverlay = MKMapRectContainsRect(mapView.visibleMapRect, theOverlay.boundingMapRect); 

    if (mapContainsOverlay) 
    { 
     // The overlay is entirely inside the map view but adjust if user is zoomed out too much... 
     double widthRatio = theOverlay.boundingMapRect.size.width/mapView.visibleMapRect.size.width; 
     double heightRatio = theOverlay.boundingMapRect.size.height/mapView.visibleMapRect.size.height; 
     if ((widthRatio < 0.6) || (heightRatio < 0.6)) //adjust ratios as needed 
     { 
      manuallyChangingMapRect = YES; 
      [mapView setVisibleMapRect:theOverlay.boundingMapRect animated:YES]; 
      manuallyChangingMapRect = NO; 
     } 
    } 
    else 
     if (![theOverlay intersectsMapRect:mapView.visibleMapRect]) 
     { 
      // Overlay is no longer visible in the map view. 
      // Reset to last "good" map rect... 
      [mapView setVisibleMapRect:lastGoodMapRect animated:YES]; 
     } 
} 

Ich habe versucht, dies mit dem eingebauten in MKCircle Overlay und scheint gut zu funktionieren.


EDIT:

Es ist gut 95% der Zeit funktioniert, aber ich habe durch einige Tests bestätigt, dass es zwischen zwei Standorten, dann geben Sie eine Endlosschleife schwingen könnte. Also, ich bearbeiten ihm ein bisschen, ich denke, das das Problem lösen soll:

// You can safely delete this method: 
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { 

} 

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 
    // prevents possible infinite recursion when we call setVisibleMapRect below 
    if (manuallyChangingMapRect) { 
     return; 
    } 

    // "theOverlay" below is a reference to your MKOverlay object. 
    // It could be an ivar or obtained from mapView.overlays array. 

    BOOL mapContainsOverlay = MKMapRectContainsRect(mapView.visibleMapRect, theOverlay.boundingMapRect); 

    if (mapContainsOverlay) { 
     // The overlay is entirely inside the map view but adjust if user is zoomed out too much... 
     double widthRatio = theOverlay.boundingMapRect.size.width/mapView.visibleMapRect.size.width; 
     double heightRatio = theOverlay.boundingMapRect.size.height/mapView.visibleMapRect.size.height; 
     // adjust ratios as needed 
     if ((widthRatio < 0.6) || (heightRatio < 0.6)) { 
      manuallyChangingMapRect = YES; 
      [mapView setVisibleMapRect:theOverlay.boundingMapRect animated:YES]; 
      manuallyChangingMapRect = NO; 
     } 
    } else if (![theOverlay intersectsMapRect:mapView.visibleMapRect]) { 
     // Overlay is no longer visible in the map view. 
     // Reset to last "good" map rect... 
     manuallyChangingMapRect = YES; 
     [mapView setVisibleMapRect:lastGoodMapRect animated:YES]; 
     manuallyChangingMapRect = NO; 
    } else { 
     lastGoodMapRect = mapView.visibleMapRect; 
    } 
} 

Und für den Fall, dass jemand für eine schnelle MKOverlay Lösung sucht, ist hier ein:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    MKCircle* circleOverlay = [MKCircle circleWithMapRect:istanbulRect]; 
    [_mapView addOverlay:circleOverlay]; 

    theOverlay = circleOverlay; 
} 

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay { 
    MKCircleView* circleOverlay = [[MKCircleView alloc] initWithCircle:overlay]; 
    [circleOverlay setStrokeColor:[UIColor mainColor]]; 
    [circleOverlay setLineWidth:4.f]; 

    return circleOverlay; 
} 
+0

Vielen Dank! Das hat den Trick gemacht. – mag725

+0

hat ganz gut funktioniert. behandelt keine Fälle, in denen Sie die Ansicht außerhalb Ihrer Grenzen schwenken (scrollen, scrollen, was auch immer). – horseshoe7

+0

@ horseshoe7, springt die Ansicht in das Overlay zurück, nachdem Sie die Geste beendet haben? Außerdem muss die Karte innerhalb des Overlays beginnen, damit das obige funktioniert.Wenn Sie _while_ einschränken müssen, während der Benutzer die Karte verschiebt, können Sie _might_ dies mit einem UIPanGestureRecognizer tun und den neuen Kartenbereich im Gestenhandler überprüfen. – Anna

4

In Mein Fall, ich musste Grenzen zu gekacheltem Overlay beschränken, das eine obere links/untenRight Koordinaten hat. Code oben funktioniert immer noch gut, aber substituierte theOverlay.boundingMapRect für MKMapRect paddedBoundingMapRect

- (void)mapView:(MKMapView *)_mapView regionDidChangeAnimated:(BOOL)animated 
{ 
if (manuallyChangingMapRect) //prevents possible infinite recursion when we call setVisibleMapRect below 
    return;  

[self updateDynamicPaddedBounds]; 

MKMapPoint pt = MKMapPointForCoordinate(mapView.centerCoordinate); 

BOOL mapInsidePaddedBoundingRect = MKMapRectContainsPoint(paddedBoundingMapRect,pt); 

if (!mapInsidePaddedBoundingRect) 
{ 
    // Overlay is no longer visible in the map view. 
    // Reset to last "good" map rect... 

    manuallyChangingMapRect = YES; 
    [mapView setVisibleMapRect:lastGoodMapRect animated:YES]; 
    manuallyChangingMapRect = NO; 


} 


-(void)updateDynamicPaddedBounds{ 

ENTER_METHOD; 

CLLocationCoordinate2D northWestPoint= CLLocationCoordinate2DMake(-33.841171,151.237318); 
CLLocationCoordinate2D southEastPoint= CLLocationCoordinate2DMake(-33.846127, 151.245058); 



MKMapPoint upperLeft = MKMapPointForCoordinate(northWestPoint); 
MKMapPoint lowerRight = MKMapPointForCoordinate(southEastPoint); 
double width = lowerRight.x - upperLeft.x; 
double height = lowerRight.y - upperLeft.y; 


MKMapRect mRect = mapView.visibleMapRect; 
MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect)); 
MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect)); 
MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMidX(mRect), MKMapRectGetMaxY(mRect)); 
MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMidX(mRect), MKMapRectGetMinY(mRect)); 

double xMidDist = abs(eastMapPoint.x - westMapPoint.x)/2; 
double yMidDist = abs(northMapPoint.y - southMapPoint.y)/2; 


upperLeft.x = upperLeft.x + xMidDist; 
upperLeft.y = upperLeft.y + yMidDist; 


double paddedWidth = width - (xMidDist*2); 
double paddedHeight = height - (yMidDist*2); 

paddedBoundingMapRect= MKMapRectMake(upperLeft.x, upperLeft.y, paddedWidth, paddedHeight); 

}

0

Anna (https://stackoverflow.com/a/4126011/3191130) -Lösung in Swift 3.0, habe ich zu einer Verlängerung:

extension HomeViewController: MKMapViewDelegate { 
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { 
    if manuallyChangingMapRect { 
     return 
    } 
    guard let overlay = self.mapOverlay else { 
     print("Overlay is nil") 
     return 
    } 
    guard let lastMapRect = self.lastGoodMapRect else { 
     print("LastGoodMapRect is nil") 
     return 
    } 

    let mapContainsOverlay = MKMapRectContainsRect(mapView.visibleMapRect, overlay.boundingMapRect) 
    if mapContainsOverlay { 
     let widthRatio: Double = overlay.boundingMapRect.size.width/mapView.visibleMapRect.size.width 
     let heightRatio: Double = overlay.boundingMapRect.size.height/mapView.visibleMapRect.size.height 
     // adjust ratios as needed 
     if (widthRatio < 0.9) || (heightRatio < 0.9) { 
      manuallyChangingMapRect = true 
      mapView.setVisibleMapRect(overlay.boundingMapRect, animated: true) 
      manuallyChangingMapRect = false 
     } 
    } else if !overlay.intersects(mapView.visibleMapRect) { 
      // Overlay is no longer visible in the map view. 
      // Reset to last "good" map rect... 
      manuallyChangingMapRect = true 
      mapView.setVisibleMapRect(lastMapRect, animated: true) 
      manuallyChangingMapRect = false 
     } 
     else { 
      lastGoodMapRect = mapView.visibleMapRect 
    } 
} 
} 

Zur Einrichtung Die Karte verwenden Sie diese:

override func viewDidLoad() { 
    super.viewDidLoad() 
    setupMap() 
} 

func setupMap() { 
    mapView.delegate = self 
    let radius:CLLocationDistance = 1000000 
    mapOverlay = MKCircle(center: getCenterCoord(), radius: radius) 
    if let mapOverlay = mapOverlay { 
     mapView.add(mapOverlay) 
    } 
    mapView.setRegion(MKCoordinateRegionMake(getCenterCoord(), getSpan()), animated: true) 
    lastGoodMapRect = mapView.visibleMapRect 
} 

func getCenterCoord() -> CLLocationCoordinate2D { 
    return CLLocationCoordinate2DMake(LAT, LON) 
} 
func getSpan() -> MKCoordinateSpan { 
    return MKCoordinateSpanMake(10, 10) 
}