MKMapView 不移动和缩放到搜索结果

Posted

技术标签:

【中文标题】MKMapView 不移动和缩放到搜索结果【英文标题】:MKMapView does not move and zoom to search results 【发布时间】:2014-07-18 10:49:14 【问题描述】:

我正在我的 MKMapView 中实现搜索,我遇到了两个问题:

    当我执行搜索时,位置会出现在结果中,并且地图会在我开始移动到目的地后移动到找到的位置。当搜索结果超出视图范围时,就会发生这种情况。如果它们在地图视图范围内或靠近,那很好。 它总是从一个搜索结果“跳跃”到另一个到用户的位置。我不希望它有这样的行为。

我已经尝试了几件事,我想问题出在:didAddAnnotationViews:

[self.locationManager stopUpdatingLocation];
MKAnnotationView *annotationView = [views objectAtIndex:0];
NSLog(@"_Here_ %@", [views description]);
id<MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 250, 250);

[mv setRegion:region animated:YES];
[self.mapView selectAnnotation:mp animated:YES];

不过,我也认为问题出在didUpdateToLocation,所以我在第一个 pin 被丢弃后禁用更新(通过搜索或点击):

- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
       fromLocation:(CLLocation *)oldLocation 

double miles = 0.3;
double scalingFactor =
ABS( cos(2 * M_PI * newLocation.coordinate.latitude /360.0) );

MKCoordinateSpan span;
span.latitudeDelta = miles/69.0;
span.longitudeDelta = miles/( scalingFactor*69.0 );

MKCoordinateRegion region;
region.span = span;
region.center = newLocation.coordinate;

[self.mapView setRegion:region animated:YES];
self.mapView.showsUserLocation = YES;

最后,搜索方法:

-(void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar

MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
[searchRequest setNaturalLanguageQuery:theSearchBar.text];
searchRequest.region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 1000, 1000);

MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:searchRequest];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) 
    if (!error) 
        NSMutableArray *annotations = [NSMutableArray array];

        [response.mapItems enumerateObjectsUsingBlock:^(MKMapItem *item, NSUInteger idx, BOOL *stop) 

            for (id<MKAnnotation>annotation in self.mapView.annotations)
            
                if (annotation.coordinate.latitude == item.placemark.coordinate.latitude &&
                    annotation.coordinate.longitude == item.placemark.coordinate.longitude)
                
                    return;
                
            

            MKPointAnnotation *addAnnotation = [[MKPointAnnotation alloc] init];
            addAnnotation.title = [item.placemark.addressDictionary objectForKey:@"Street"];
            addAnnotation.coordinate = item.placemark.coordinate;

            [annotations addObject:addAnnotation];
        ];
        for (id<MKAnnotation>annotation in self.mapView.annotations) 
            [self.mapView removeAnnotation:annotation];
        
        [self.mapView addAnnotations:annotations];

     else 
        NSLog(@"Search Request Error: %@", [error localizedDescription]);
    
];

//Hide the keyboard.
[self.searchBar resignFirstResponder];

我的目标是创建一个 MapView,用户可以在其中通过点击或搜索固定位置,并且显然可以查看搜索结果。

【问题讨论】:

【参考方案1】:

对于第一个问题:

当我执行搜索时,位置出现在结果中并且地图移动到 只有在我开始移动到目的地之后才找到位置。这 当搜索结果超出视图范围时发生。如果他们 在地图视图范围内或附近都可以。

发生这种情况是因为您将地图移动到在didAddAnnotationViews 委托方法中找到的注释(至少是第一个)。

但是只有当注释在可见区域时才会调用该委托方法。如果注释被添加到地图但它不在可见区域(还),viewForAnnotation 将不会被调用,因此didAddAnnotationViews 将不会被调用。

然后,当您手动移动地图时,添加的注释开始进入可见区域,然后调用委托方法,地图突然跳转到其中一个注释。

不要在didAddAnnotationViews 委托方法中调用setRegion

有时,这样做还会导致viewForAnnotationdidAddAnnotationViews 调用的无限循环,因为当区域更改时,它会导致看到以前没有的其他注释,因此viewForAnnotation 被调用并然后didAddAnnotationViews 被调用,以此类推。

相反,在searchBarSearchButtonClicked: 方法中调用addAnnotations:(或者更好,只需调用showAnnotations:)之后立即设置区域。

我还会从didAddAnnotationViews 中删除对stopUpdatingLocation 的调用。如果您将地图的 showsUserLocation 设置为 YES,您可能甚至根本不需要位置管理器。

对于第二个问题:

它总是从一个搜索结果“跳跃”到另一个搜索结果或 用户的位置。我不希望它有这样的行为。

这部分是由于在didAddAnnotationViews 中调用了setRegion,还因为在didUpdateToLocation 中调用了setRegion

因此,由于第一个问题所描述的原因,两个委托方法和用户的手动移动相互争斗,地图最终跳来跳去。

不要在 didUpdateToLocation 方法中调用 setRegion(或者,通过在 BOOL 中跟踪是否已缩放到用户位置与否)。

不影响行为,但在didUpdateToLocation 中将showsUserLocation 设置为YES 没有意义。为什么不在viewDidLoad 中设置它或在storyboard/xib 中打开它?

此外,无需像那样手动计算区域跨度(最好让 MapKit 为您完成这项工作)。只需将英里转换为米并致电MKCoordinateRegionMakeWithDistance

【讨论】:

如果它对您有用,您可以将 selectAnnotation 保留在该委托方法中。到目前为止显示的代码应该没有问题。

以上是关于MKMapView 不移动和缩放到搜索结果的主要内容,如果未能解决你的问题,请参考以下文章

地图缩放时,别针上的弹出框不移动

防止 MKMapView 不断地重新缩放和重新居中到用户位置

MKMapView 缩放以显示框架中的所有注释

SwiftUI 上的按钮点击调用 MKMapView.setRegion

将 MKMapView 缩放到 MKAnnotationView 的框架

MKMapView 缩放和区域