Tracking Mkmapview Centercoordinate While Panning

Tracking MKMapView centerCoordinate while panning

I suggest not using an actual id<MKAnnotation> at all (at least for this "current location setting" mode).

Instead:

  1. Add a view (eg. UIImageView) containing an image of a pin (or whatever icon you like) in front of the map view.
  2. This pin view should not be a subview of the map view.
  3. The pin view should be a subview of the same view that the map view is a subview of (eg. both should be subviews of the same superview).
  4. The pin view should be sized and positioned such that it appears above the center of the map view (you could make the pin view have the same frame and the same autolayout/autoresizing logic as the map view so they stay visually synchronized regardless of screen size or orientation).
  5. If using a UIImageView, set its content mode to "center" and background color to "clear" (default is clear).
  6. The pin view should have user interaction disabled on it so that the user can still interact with the map view behind it. As the user pans or zooms the map view, the pin view in front will seem to move instantly.
  7. If necessary, the app can get the location coordinates from mapView.centerCoordinate in the regionDidChangeAnimated: MKMapViewDelegate method (or pan/pinch gesture recognizers) or only when the user says they're done positioning. I don't recommend using a timer (especially every 0.00001s) to query the current center coordinate.
  8. When the user indicates that the current position is where they want to finally place the annotation, you can then create and add an actual annotation at that coordinate and hide the "location setting mode" pin view.

Detecting panning + decelerate of MKMapView

Answering myself. I implemented all of MKMapViewDelegate's methods and it seems that

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated

is called on pan, and

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

is called as soon as deceleration stops (and not before).

Maintain centre coordinate while pinching MKMapView

When the user pinches the screen on the actual device (as opposed to the simulator), it causes both a pan and a pinch gesture – the pinch contains the "zoom" element of the motion, and the pan contains the vertical and horizontal change. You need to be intercepting and blocking the pan, and that means using a UIPanGestureRecognizer.

Set scrollEnabled to NO, then add a UIPanGestureRecognizer to reset the center coordinate. The combination will block both single-finger panning and the pan component of a pinch.


Edit to add more details, and after seeing your code: touchesMoved:withEvent is called after the pan has already begun, so if you change the MKMapView's center there, you'll get the herky-jerky rendering problems you've described. What you really need is to create a UIPanGestureRecognizer with a target-action, like so:

    UIPanGestureRecognizer *pan = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didRecognizePan)] autorelease];
pan.delegate = self;
[self.mapView addGestureRecognizer:pan];

...and then add a didRecognizePan method to your controller, and do your center-resetting there.

Center of map and center of screen are different

It would be best to offset the fake annotation down by the height of the tab bar. You can read the tab bar height and then add that to the .y value of fake annotation.

MKMapView panning causes parent UIScrollView to scroll

The expected outcome is correct, the scroll view should remain stationary when the Map View is touched, as this should receive the touch events before they are passed up the responder chain to the scroll view.

I have quickly tested the above code in an empty project, and this is working as expected with a couple of alterations to the creating of frame & sizes, iPad size detection, and adding the map as a sub-view of the scroll view.

UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[scrollView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
// Make the content size large to allow scroll view to move
[scrollView setContentSize:CGSizeMake(1000, 2000)];
[self.view addSubview:scrollView];

double mapHeight = 200;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
mapHeight = 400;
}

MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, mapHeight)];
[map setExclusiveTouch:NO];
[scrollView addSubview:map];

Having Placemark/Annotation in the center of your mapView, even if you scroll

Found my question in How to add annotation on center of map view in iPhone?

There's the answer :

If you want to use an actual annotation instead of just a regular view positioned above the center of the map view, you can:

  • use an annotation class with a settable coordinate property (pre-defined MKPointAnnotation class eg). This avoids having to remove and add the annotation when the center changes.
  • create the annotation in viewDidLoad
  • keep a reference to it in a property, say centerAnnotation
  • update its coordinate (and title, etc) in the map view's regionDidChangeAnimated delegate method (make sure map view's delegate property is set)

Example:

@interface SomeViewController : UIViewController <MKMapViewDelegate> {
MKPointAnnotation *centerAnnotation;
}
@property (nonatomic, retain) MKPointAnnotation *centerAnnotation;
@end

@implementation SomeViewController

@synthesize centerAnnotation;

- (void)viewDidLoad {
[super viewDidLoad];

MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = mapView.centerCoordinate;
pa.title = @"Map Center";
pa.subtitle = [NSString stringWithFormat:@"%f, %f", pa.coordinate.latitude, pa.coordinate.longitude];
[mapView addAnnotation:pa];
self.centerAnnotation = pa;
[pa release];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:@"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}

- (void)dealloc {
[centerAnnotation release];
[super dealloc];
}

@end

Now this will move the annotation but not smoothly. If you need the annotation to move more smoothly, you can add a UIPanGestureRecognizer and UIPinchGestureRecognizer to the map view and also update the annotation in the gesture handler:

    // (Also add UIGestureRecognizerDelegate to the interface.)

// In viewDidLoad:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
[panGesture release];

UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
pinchGesture.delegate = self;
[mapView addGestureRecognizer:pinchGesture];
[pinchGesture release];

- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:@"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//let the map view's and our gesture recognizers work at the same time...
return YES;
}

How to add annotation on center of map view in iPhone?

If you want to use an actual annotation instead of just a regular view positioned above the center of the map view, you can:

  • use an annotation class with a settable coordinate property (pre-defined MKPointAnnotation class eg). This avoids having to remove and add the annotation when the center changes.
  • create the annotation in viewDidLoad
  • keep a reference to it in a property, say centerAnnotation
  • update its coordinate (and title, etc) in the map view's regionDidChangeAnimated delegate method (make sure map view's delegate property is set)

Example:

@interface SomeViewController : UIViewController <MKMapViewDelegate> {
MKPointAnnotation *centerAnnotation;
}
@property (nonatomic, retain) MKPointAnnotation *centerAnnotation;
@end

@implementation SomeViewController

@synthesize centerAnnotation;

- (void)viewDidLoad {
[super viewDidLoad];

MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = mapView.centerCoordinate;
pa.title = @"Map Center";
pa.subtitle = [NSString stringWithFormat:@"%f, %f", pa.coordinate.latitude, pa.coordinate.longitude];
[mapView addAnnotation:pa];
self.centerAnnotation = pa;
[pa release];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:@"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}

- (void)dealloc {
[centerAnnotation release];
[super dealloc];
}

@end

Now this will move the annotation but not smoothly. If you need the annotation to move more smoothly, you can add a UIPanGestureRecognizer and UIPinchGestureRecognizer to the map view and also update the annotation in the gesture handler:

    // (Also add UIGestureRecognizerDelegate to the interface.)

// In viewDidLoad:
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
panGesture.delegate = self;
[mapView addGestureRecognizer:panGesture];
[panGesture release];

UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
pinchGesture.delegate = self;
[mapView addGestureRecognizer:pinchGesture];
[pinchGesture release];

- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
centerAnnotation.coordinate = mapView.centerCoordinate;
centerAnnotation.subtitle = [NSString stringWithFormat:@"%f, %f", centerAnnotation.coordinate.latitude, centerAnnotation.coordinate.longitude];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
//let the map view's and our gesture recognizers work at the same time...
return YES;
}


Related Topics



Leave a reply



Submit