确定是否拖动/移动MKMapView
有没有一种方法来确定是否一个MKMapView被拖动?
每当用户使用CLLocationCoordinate2D centre = [locationMap centerCoordinate];
拖动地图时,我想获取中心位置CLLocationCoordinate2D centre = [locationMap centerCoordinate];
但是我需要一个委托方法或者一旦用户在地图上浏览时触发的东西。
提前致谢
看看MKMapViewDelegate参考。
具体来说,这些方法可能是有用的:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
确保你的地图视图的委托属性被设置,以便这些方法被调用。
接受的答案中的代码在由于任何原因而改变区域时触发。 要正确地检测地图拖动,您必须添加一个UIPanGestureRecognizer。 顺便说一句,这是拖动手势识别器(平移=拖动)。
第1步:在viewDidLoad中添加手势识别器:
-(void) viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer* panRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didDragMap:)]; [panRec setDelegate:self]; [self.mapView addGestureRecognizer:panRec]; }
第2步:将协议UIGestureRecognizerDelegate添加到视图控制器,以便它作为委托。
@interface MapVC : UIViewController <UIGestureRecognizerDelegate, ...>
步骤3:为UIPanGestureRecognizer添加以下代码,以便与MKMapView中已有的手势识别器配合使用:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }
第四步:如果你想调用你的方法一次,而不是每次拖动50次,检测到在select器中的“拖拽结束”状态:
- (void)didDragMap:(UIGestureRecognizer*)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ NSLog(@"drag ended"); } }
这是我工作的唯一方式,检测平移以及由用户发起的缩放更改:
- (BOOL)mapViewRegionDidChangeFromUserInteraction { UIView *view = self.mapView.subviews.firstObject; // Look through gesture recognizers to determine whether this region change is from user interaction for(UIGestureRecognizer *recognizer in view.gestureRecognizers) { if(recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateEnded) { return YES; } } return NO; } static BOOL mapChangedFromUserInteraction = NO; - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { mapChangedFromUserInteraction = [self mapViewRegionDidChangeFromUserInteraction]; if (mapChangedFromUserInteraction) { // user changed map region } } - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { if (mapChangedFromUserInteraction) { // user changed map region } }
(只是) @ mobi的优秀解决scheme的迅捷版本:
private var mapChangedFromUserInteraction = false private func mapViewRegionDidChangeFromUserInteraction() -> Bool { let view = self.mapView.subviews[0] // Look through gesture recognizers to determine whether this region change is from user interaction if let gestureRecognizers = view.gestureRecognizers { for recognizer in gestureRecognizers { if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) { return true } } } return false } func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) { mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction() if (mapChangedFromUserInteraction) { // user changed map region } } func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { if (mapChangedFromUserInteraction) { // user changed map region } }
您还可以在Interface Builder中将地图识别器添加到地图中。 把它连接到你的viewController的动作sockets,我叫我的“mapDrag”…
然后,你会在你的viewController的.m中做这样的事情:
- (IBAction)mapDrag:(UIPanGestureRecognizer *)sender { if(sender.state == UIGestureRecognizerStateBegan){ NSLog(@"drag started"); } }
确保你也有这个:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }
当然你必须在你的.h文件中使你的viewController成为一个UIGestureRecognizerDelegate才能工作。
否则,地图的响应者是唯一听到手势事件的人。
另一个可能的解决scheme是在视图控制器中实现touchesMoved :(或touchesEnded:等),它包含你的地图视图,如下所示:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; for (UITouch * touch in touches) { CGPoint loc = [touch locationInView:self.mapView]; if ([self.mapView pointInside:loc withEvent:event]) { #do whatever you need to do break; } } }
在某些情况下,这可能比使用手势识别器更简单。
根据我的经验,类似于“键入时search”,我发现一个计时器是最可靠的解决scheme。 它不需要添加额外的手势识别器来平移,捏,旋转,敲击,双击等等。
解决scheme很简单:
- 当地图区域更改时,设置/重置定时器
-
计时器激发时,加载新区域的标记
import MapKit class MyViewController: MKMapViewDelegate { @IBOutlet var mapView: MKMapView! var mapRegionTimer: NSTimer? // MARK: MapView delegate func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { setMapRegionTimer() } func setMapRegionTimer() { mapRegionTimer?.invalidate() // Configure delay as bet fits your application mapRegionTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "mapRegionTimerFired:", userInfo: nil, repeats: false) } func mapRegionTimerFired(sender: AnyObject) { // Load markers for current region: // mapView.centerCoordinate or mapView.region } }
要识别mapview上的任何手势何时结束:
http://b2cloud.com.au/tutorial/mkmapview-determining-whether-region-change-is-from-user-interaction/
这对于用户完成缩放/旋转/拖动地图后仅执行数据库查询非常有用。
对于我而言,regionDidChangeAnimated方法只在手势完成后才被调用,拖动/缩放/旋转时不会被调用很多次,但是知道是否是由于手势而非常有用。
Swift 3解决scheme给Jano上面的答案 :
将协议UIGestureRecognizerDelegate添加到您的ViewController
class MyViewController: UIViewController, UIGestureRecognizerDelegate
在viewDidLoad
创buildUIPanGestureRecognizer并将delegate
设置为self
viewDidLoad() { // add pan gesture to detect when the map moves let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.didDragMap(_:))) // make your class the delegate of the pan gesture panGesture.delegate = self // add the gesture to the mapView mapView.addGestureRecognizer(panGesture) }
添加一个协议方法,以便您的手势识别器将与现有的MKMapView手势一起工作
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }
在平移手势中添加将由select器调用的方法
func didDragMap(_ sender: UIGestureRecognizer) { if sender.state == .ended { // do something here } }
在这里input代码我设法做到这一点最简单的方法,它处理所有的交互与地图(轻拍/双/ N轻拍用1/2 / N的手指,泛1/2 / N的手指,捏和旋转
- 创build
gesture recognizer
并添加到地图视图的容器 - 将
gesture recognizer's
delegate
设置为实现UIGestureRecognizerDelegate
某个对象 - 实现
gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch)
方法
private func setupGestureRecognizers() { let gestureRecognizer = UITapGestureRecognizer(target: nil, action: nil) gestureRecognizer.delegate = self self.addGestureRecognizer(gestureRecognizer) } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { self.delegate?.mapCollectionViewBackgroundTouched(self) return false }
很多这些解决scheme都是基于hacky /而不是Swift预期的方面,所以我select了一个更清晰的解决scheme。
我只是inheritanceMKMapView并覆盖touchesMoved。 虽然这个片段没有包括它,但我build议创build一个委托或通知来传递你想要的关于移动的任何信息。
import MapKit class MapView: MKMapView { override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesMoved(touches, with: event) print("Something moved") } }
您将需要更新故事板文件中的类以指向此子类,以及通过其他方式修改您创build的任何地图。
我试图在总是位于地图中心的地图中心注释一个注释,不pipe用途如何。 我尝试了上面提到的几种方法,但都不够好。 我最终find了解决这个问题的一个非常简单的方法,借鉴了Anna的答案,并与Eneko的答案相结合。 它基本上将regionWillChangeAnimated作为拖动的开始,而regionDidChangeAnimated作为一个结束,并使用计时器实时更新引脚:
var mapRegionTimer: Timer? public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) { mapRegionTimer?.invalidate() mapRegionTimer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { (t) in self.myAnnotation.coordinate = CLLocationCoordinate2DMake(mapView.centerCoordinate.latitude, mapView.centerCoordinate.longitude); self.myAnnotation.title = "Current location" self.mapView.addAnnotation(self.myAnnotation) }) } public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { mapRegionTimer?.invalidate() }