22

一旦用户开始捏MKMapView ,这scrollEnabled似乎是易碎的。

您仍然不能用一根手指滚动,但如果在放大和缩小时用两根手指滚动,您可以移动地图。

我试过了 :

  • 子类化MKMapKit以禁用其中的滚动视图。
  • 实现 –<code>mapView:regionWillChangeAnimated: 来强制中心。
  • 禁用scrollEnabled.

但没有运气。

谁能告诉我一个只放大MKMapView的可靠方法,所以中心点总是保持在中间?

4

6 回答 6

31

您可以尝试使用以下方法自己处理捏合手势UIPinchGestureRecognizer

首先设置scrollEnabledzoomEnabled创建NO手势识别器:

UIPinchGestureRecognizer* recognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
                                                                                 action:@selector(handlePinch:)];
[self.mapView addGestureRecognizer:recognizer];

在识别器处理程序中MKCoordinateSpan根据缩放比例调整:

- (void)handlePinch:(UIPinchGestureRecognizer*)recognizer
{
    static MKCoordinateRegion originalRegion;
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        originalRegion = self.mapView.region;
    }    

    double latdelta = originalRegion.span.latitudeDelta / recognizer.scale;
    double londelta = originalRegion.span.longitudeDelta / recognizer.scale;

    // TODO: set these constants to appropriate values to set max/min zoomscale
    latdelta = MAX(MIN(latdelta, 80), 0.02);
    londelta = MAX(MIN(londelta, 80), 0.02);
    MKCoordinateSpan span = MKCoordinateSpanMake(latdelta, londelta);

    [self.mapView setRegion:MKCoordinateRegionMake(originalRegion.center, span) animated:YES];
}

这可能不像 Apple 的实现那样完美,但它应该可以解决您的问题。

于 2012-08-14T14:20:37.723 回答
4

Swift 3.0 版本的@Paras Joshi 回答https://stackoverflow.com/a/11954355/3754976

带有小动画修复。

class MapViewZoomCenter: MKMapView {

    var originalRegion: MKCoordinateRegion!

    override func awakeFromNib() {
       self.configureView()
    }

    func configureView() {
        isZoomEnabled = false
        self.registerZoomGesture()
    }

    ///Register zoom gesture
    func registerZoomGesture() {
        let recognizer = UIPinchGestureRecognizer(target: self, action:#selector(MapViewZoomCenter.handleMapPinch(recognizer:)))
        self.addGestureRecognizer(recognizer)
    }

    ///Zoom in/out map
    func handleMapPinch(recognizer: UIPinchGestureRecognizer) {

        if (recognizer.state == .began) {
            self.originalRegion = self.region;
        }

        var latdelta: Double = originalRegion.span.latitudeDelta / Double(recognizer.scale)
        var londelta: Double = originalRegion.span.longitudeDelta / Double(recognizer.scale)

        //set these constants to appropriate values to set max/min zoomscale
        latdelta = max(min(latdelta, 80), 0.02);
        londelta = max(min(londelta, 80), 0.02);

        let span = MKCoordinateSpanMake(latdelta, londelta)

        self.setRegion(MKCoordinateRegionMake(originalRegion.center, span), animated: false)

    }
}
于 2017-02-01T11:33:20.950 回答
1

尝试在您的地图视图的委托中实现–mapView:regionWillChangeAnimated:–mapView:regionDidChangeAnimated:,以便地图始终以您的首选位置为中心。

于 2012-08-06T15:46:15.700 回答
1

我以前读过这个,虽然我从来没有真正尝试过。看看这篇关于带边界的 MKMapView 的文章。它使用两个委托方法来检查视图是否已被用户滚动。

http://blog.jamgraham.com/blog/2012/04/29/adding-boundaries-to-mkmapview

本文描述了一种与您尝试过的方法类似的方法,因此,如果您已经偶然发现它,请见谅。

于 2012-08-09T13:48:53.237 回答
1

这些答案中的任何一个我都没有运气。自己捏捏太矛盾了。我遇到了正常变焦比我自己捏的更远的情况。

最初,我尝试作为原始海报执行以下操作:

- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    MKCoordinateRegion region = mapView.region;
    //...
    // adjust the region.center 
    //...
    mapView.region = region;
}

我发现那没有效果。我还通过NSLogs 发现即使我以编程方式设置regionor时,此方法也会触发。centerCoordinate这导致了一个问题:“如果它确实有效,上述内容不会无限吗?”

所以我现在推测和假设,当用户缩放/滚动/旋转发生时,MapView 会以某种方式抑制或忽略对该区域的更改。关于仲裁的某些事情使程序化调整无能为力。

如果这是问题所在,那么也许关键是在regionDidChanged:通知之外进行区域调整。并且由于任何调整都会触发另一个通知,因此能够确定何时不再调整非常重要。这导致我进行了以下实现(在哪里subject提供我想留在中间的中心坐标):

- (void) recenterMap {
    double latDiff = self.subject.coordinate.latitude self.mapView.centerCoordinate.latitude;
    double lonDiff = self.subject.coordinate.longitude - self.mapView.centerCoordinate.longitude;
    BOOL latIsDiff = ABS(latDiff) > 0.00001;
    BOOL lonIsDiff = ABS(lonDiff) > 0.00001;
    if (self.subject.isLocated && (lonIsDiff || latIsDiff)) {
        [self.mapView setCenterCoordinate: self.subject.coordinate animated: YES];
    }
}

- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    if (self.isShowingMap) {
        if (self.isInEdit) {
            self.setLocationButton.hidden = NO;
            self.mapEditPrompt.hidden = YES;
        }
        else {
            if (self.subject.isLocated) { // dispatch outside so it will happen after the map view user events are done
                 dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^{
                    [self recenterMap];
                });
            }
        }
    }
}

它向后滑动的延迟可能会有所不同,但它确实工作得很好。并让地图交互在发生时保持 Apple 风格。

于 2015-05-14T00:32:45.143 回答
1

我试过这个并且它有效。

首先创建一个属性:

var originalCenter: CLLocationCoordinate2D?

然后在 regionWillChangeAnimated 中,检查这个事件是否是由 UIPinchGestureRecognizer 引起的:

func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
    let firstView = mapView.subviews.first
    if let recognizer = firstView?.gestureRecognizers?.filter({ $0.state == .Began || $0.state == .Ended }).first as? UIPinchGestureRecognizer {
        if recognizer.scale != 1.0 {
            originalCenter = mapView.region.center
        }
    }
}

然后在 regionDidChangeAnimated 中,如果捏合手势导致区域发生变化,则返回原始区域:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    if let center = originalCenter {
        mapView.setRegion(MKCoordinateRegion(center: center, span: mapView.region.span), animated: true)
        originalCenter = nil
        return
    }
// your other code 
}
于 2016-01-23T01:56:56.587 回答