2010-11-07 58 views
9

我試圖將一個自定義圖像添加到MKMapView作爲MKOverlayView - 我需要限制用戶無法在覆蓋範圍外滾動。有沒有現有的功能來做到這一點?還是有其他建議?限制MKMapView滾動

謝謝,馬特

回答

18

如果你只想在覆蓋凍結地圖視圖,你可以在地圖視圖的區域設置爲疊加層的邊界,並設置scrollEnabledzoomEnabledNO

但是,這不會讓用戶滾動或縮放覆蓋的界限內。

有沒有內置的方式來限制地圖視圖覆蓋的界限,所以你必須手動做。首先,確保您的MKOverlay對象實現boundingMapRect屬性。然後可以在regionDidChangeAnimated委託方法中根據需要手動調整視圖。

下面是一個如何做到這一點的例子。
下面的代碼應該在具有MKMapView的類中。
確保地圖視圖最初設置爲覆蓋層可見的區域。

//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]; 
     } 
} 

我試圖與內置MKCircle疊加和似乎運作良好。


編輯:

,它工作的時間以及95%,但是,我已經通過一些測試,它可能在兩個位置之間振盪確認,然後進入一個無限循環。所以,我編輯了一點,我想這應該解決的問題:

// 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; 
    } 
} 

以防萬一有人在尋找一種快速MKOverlay解決方案,這裏是一個:

- (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

謝謝!那就是訣竅。 – mag725 2010-11-13 00:52:23

+0

工作得很好。但不處理您在範圍之外平移(滑動,滾動,任意)的情況。 – horseshoe7 2011-07-20 19:07:08

+0

@ horseshoe7,結束姿勢後,視圖是否會重新回到疊加層?此外,地圖必須在覆蓋層內部開始才能工作。如果您需要限制_while_用戶正在移動地圖,您可以使用UIPanGestureRecognizer並檢查手勢處理程序中的新地圖區域。 – Anna 2011-07-20 19:29:33

4

在我的情況,我需要限制到具有左上角/右下角座標的平鋪疊加。以上代碼仍然運作良好,但取代theOverlay.boundingMapRect爲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

在夫特3.0安娜的(https://stackoverflow.com/a/4126011/3191130)溶液,我添加到延伸:

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 
    } 
} 
} 

要設置該地圖使用此:

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) 
}