viewForAnnotation didn't moves the userLocation - ios

I've implemented - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { method to change the default location of userLocation Annotation. Inside this method I've used:
if (annotation==(mapView.userLocation)) {
MKAnnotationView *myAnotation = [[MKAnnotationView alloc] init];
myAnotation.image = self.userPointImage.image;
myAnotation.centerOffset = CGPointMake(0, 250);
return myAnotation;
}
else
{
return nil;
}
Which successfully moves the default userLocation annotation to center bottom. But as I'm also using heading so when move my phone it is still rotating the map from center.
- (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading {
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:true];
}
But the userLocation annotation is below. So how to do that?
UPDATE I found this question and tried applying it. But as I'm using heading so it crashes the app.
In my didUpdateUserLocation method I added [self moveCenterByOffset:CGPointMake(0, 200) from:userLocation.coordinate]; and this method is as follows:
- (CLLocationCoordinate2D)moveCenterByOffset:(CGPoint)offset from:(CLLocationCoordinate2D)coordinate
{
CGPoint point = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView];
point.x += offset.x;
point.y += offset.y;
CLLocationCoordinate2D center = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
return center;
}
and then in my didUpdateUserLocation method I updated it as: MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([self moveCenterByOffset:CGPointMake(0, -250) from:userLocation.coordinate], 800.0f, 200.0f); and [mapView setRegion:region animated:NO]; as I'm using heading so animation is set to NO. But now as I run the code it starts jerking between center and the new point.

MKCoordinateRegion region = mapClinicsView.region;
set 'region.center'
It will helps you to navigate your map center position
make sure 'region.center' and annotation center latitute and longitute is same

Related

Detect touch nearby to CLLocationCoordinate2D in pixels

I have few GMSMarker on GMSMapView, all of them are draggable, so when I longpress them, I can move them around the map. However I have also an action on longpress on GMSMapView, which adds a marker.
- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker {
self.moving = YES;
}
- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker {
self.moving = NO;
}
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate {
if (self.moving) {
return;
}
[self addMarkerAtCoordinate:coordinate];
}
Now the problem is, that sometimes user mistap and instead of moving marker he adds a new one. Because of this, I'd like to add small area around marker, where user can't add new markers. I've thought about something like this:
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate {
CGFloat zoomFactor = 35.f - self.mapView.camera.zoom;
CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
for (GMSMarker *marker in self.markers) {
CLLocation *sectorLocation = [[CLLocation alloc] initWithLatitude:marker.position.latitude longitude:marker.position.longitude];
if ([location distanceFromLocation:sectorLocation] < zoomFactor) {
return;
}
}
}
But of course I don't like this solution, because the area is changing with changed zoom. I'd like something like a finger width around marker to be longpress banned. How to calculate this distance?
It's easy to convert coordinate to location on view using method pointForCoordinate: on GMSProjection GMSMapView object.
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate {
CGPoint longpressPoint = [mapView.projection pointForCoordinate:coordinate];
for (GMSMarker *marker in self.markers) {
CLLocationCoordinate2D markerCoordinate = marker.position;
CGPoint sectorPoint = [mapView.projection pointForCoordinate:markerCoordinate];
if (fabsf(longpressPoint.x - markerCoordinate.x) < 30.f && fabsf(longpressPoint.y - markerCoordinate.y) < 30.f) { // 30.f ofc should be defined as constant
// handle situation when touchpoint is too close to marker
}
}
}

MKMapView: annotation's callout not shown when setting region

I show several custom annotation views on an MKMapView, and when user taps one of them, I change the region to be centered on it:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view.annotation isKindOfClass:[CustomAnnotation class]]) {
double miles = 2.5;
double scalingFactor = ABS(cos(2 * M_PI * lat / 360.0));
MKCoordinateSpan span;
span.latitudeDelta = miles/69.0;
span.longitudeDelta = miles/(scalingFactor * 69.0);
MKCoordinateRegion region;
region.span = span;
region.center = self.coordinates;
[self.mapView setRegion:region animated:YES];
}
}
I see that, when the annotation already was shown, more or less, in the center of the map, the callout is displayed, but it is not when I tap an annotation closer to the map's border and the region has to "move more". I tried to select the annotation after the region setting animation ends:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
for (id annotation in self.mapView.annotations) {
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
if (((CustomAnnotation *)annotation).id == self.selectedAnnotation.id) {
[self.mapView selectAnnotation:annotation animated:YES];
}
}
}
}
But the callout is neither shown. If I don't change programmatically the region when tapping, all callouts are shown. How could I solve this?
Thanks

Incorrect user location shown on MKMapView after scaling the map programmatically

I have MKMapView which have UserTrackingMode = MKUserTrackingModeFollow,
and I have adding a circle overlay to show a region of the certain diameter at user location.
Also user can change the diameter of the region so I want to scale the map to insure whole region/circle is shown on that portion of the map.
The problem I have now is that scaling the map number of times by setting region results in incorrect user location annotation - it is moved from the correct location.
I cannot understand why is that happens, I see in the debugger that the mapView.userLocation property have correct coordinates.
But once new update is happens or I move the map manually - the annotation jumps to the correct place.
This is the code:
- (void)addCircleWithRadius:(double)radius andCoordinate:(CLLocationCoordinate2D)coordinate
{
_regionCircle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius];
[_regionCircle setTitle:#"Region"];
MKCoordinateRegion region;
region.center.latitude = coordinate.latitude;
region.center.longitude = coordinate.longitude;
region.span.latitudeDelta = 0.00002 * _regionCircle.radius;
region.span.longitudeDelta = 0.00002 * _regionCircle.radius;
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits: region];
[self.mapView setRegion:adjustedRegion animated:TRUE];
_circleView = nil;
[self.mapView addOverlay:_regionCircle];
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
if(!_circleView)
{
_circleView = [[MKCircleView alloc] initWithCircle:overlay];
_circleView.strokeColor = [UIColor blueColor];;
_circleView.fillColor = [UIColor blueColor];
_circleView.alpha = 0.25;
_circleView.lineWidth = 2.0;
}
return _circleView;
}
- (IBAction)regionSliderValueChanged:(id)sender
{
[self updateRadiusCircle];
}
- (void) updateRadiusCircle
{
[self.mapView removeOverlays:self.mapView.overlays];
CLLocationCoordinate2D myCoordinate = {_currentLocation.coordinate.latitude, _currentLocation.coordinate.longitude};
[self addCircleWithRadius:self.radiusSlider.value andCoordinate:myCoordinate];
}
I have published the video on YouTube to better understand the issue.
https://www.youtube.com/watch?v=474gdjkGwJA

MKMapKit iOS 5. Can I set a desired delegate when I want?

I have a question about map and delegate. I am doing a exercise from a book and it says to me to use the method
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//CLLocationCoordinate2D loc = [userLocation coordinate];
self.coord2D = [userLocation coordinate];
//MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coord2D, 250, 250);
[worldView setRegion:region animated:YES];
}
Which means every time I move my phone from my location it will show myself on screen. I also create a button that calls this method. Therefore if I am scrolling my map I can see where I am.
The problem is: if I am in a car and want to scroll my map it will become a difficult task due this method will be call all the time I change my location.
Is there any other method or if I have an option to activate and deactivate a delegate?
Thanks in advance.
As far as I can tell it's quite simple. Just have a button for activating and deactivating it.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//CLLocationCoordinate2D loc = [userLocation coordinate];
self.coord2D = [userLocation coordinate];
if (self.trackUserLocation) {
//MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coord2D, 250, 250);
[worldView setRegion:region animated:YES];
}
}
The property:
#property (nonatomic, assign) BOOL trackUserLocation;
The button action:
self.trackUserLocation = !self.trackUserLocation;
You don't have to make it any harder than that.

MKMapView - Limit map scroll to a square overlay

I have a MKMapView with a square overlay described as:
CLLocationCoordinate2D coordsBg[5]={
CLLocationCoordinate2DMake(31.750865,35.180882),
CLLocationCoordinate2DMake(31.740331,35.180882),
CLLocationCoordinate2DMake(31.740331,35.165452),
CLLocationCoordinate2DMake(31.750865,35.165452),
CLLocationCoordinate2DMake(31.750865,35.180882)
};
MKPolygon *bg=[MKPolygon polygonWithCoordinates:coordsBg count:5];
[map addOverlay:bg];
I wish to limit the user from scrolling outside of the overlay.
Can I limit the MKMapView scroll view for that? Or there is an other method?
Thanks
Shani
After Few hours of banging my head, I got to this solution that work great for me.
It mixes up :
This post: set the zoom level of an mkmapview
And This link: restrict mkmapview scrolling from #Anna Karenina comment to my question.
And This is my code:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
lastGoodMapRect = mapView.visibleMapRect;
lastGoodRegion = mapView.region;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (manuallyChangingMapRect) {
manuallyChangingMapRect=NO;
return;
}
if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}
MKMapRect visibleRect = mapView.visibleMapRect;
MKMapRect OverlayRect = bg.boundingMapRect;
MKMapRect intersectionRect = MKMapRectIntersection(visibleRect,OverlayRect);
//you can change the min and max zoom off course
if(!MKMapRectEqualToRect(visibleRect,intersectionRect)){
if( [mapView zoomLevel] < 15){
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:15 animated:YES];
}else if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}else{
manuallyChangingMapRect=YES;
[mapView setVisibleMapRect:lastGoodMapRect animated:YES];
}
}
}

Resources