I am trying to use some delegate methods in MKMapViewDelegate. Specifically, I want to give the pop out an accessory arrow so that when user touches it, it launches native map application (for full blown mapping functions.)
I think I understand correctly that once the VC is set up as a delegate of itself then the protocol methods get called automatically. In that case do delegate methods get called automatically or do you have to do something else?
Here is method to launch map.
-(void) geoCodeAndMapIt {
NSString* location = #"156 University Ave, Palo Alto, CA 94301";
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc]
initWithPlacemark:topResult];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(placemark.coordinate, 5000, 5000);//5000 is meters
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
[self.mapView setRegion:region animated:YES];
[self.mapView addAnnotation:placemark];
}
Here is method that should add accessory arrow to callout but is not firing:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"loc"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
How do I get this method to fire so I get accessory arrow? Thanks for any suggestions.
Why don't you use this method when you click the button in you annotation view this method is fired and you can perform your custom action there.
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
//Do whatever you want to do here.
PropertyLocation *location = (PropertyLocation*)view.annotation;
for(PropertyDTO *property in self.items)
{
if(property.location == location)
{
PropertyDetailVC *detailVC = [PropertyDetailVC propertyDetailVCWithNodeID:property.nodeID];
[self.navigationController pushViewController:detailVC animated:YES];
}
}
}
Related
I'm using the Apple maps. At the moment I have to click on one of my Annotation Pins and the Annotation View is opening, than I can click on this view and something happens. But i want to click on my Annotation Pins and the Map should be zoom in WITHOUT opening the Annotation View first. I tried this, but it doesn't work:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if(someValues > 1){
//If someValues are bigger than one then only zoom in without returning the annotation View
MKCoordinateRegion region = mapView.region;
MKCoordinateSpan span;
span.latitudeDelta = region.span.latitudeDelta/5;
span.longitudeDelta = region.span.longitudeDelta/5;
region.span = span;
region.center = anntotation.coordinate;
[mapView setRegion:region animated:TRUE];
//return 0 returns a default view i know....whats correct?
return 0;
} else {
MKPinAnnotationView *view = nil;
if (annotation != mapView.userLocation)
{
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"identifier"];
if (nil == view) {
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"identifier"];
}
[view setPinColor:MKPinAnnotationColorRed];
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[view setCanShowCallout:YES];
[view setAnimatesDrop:NO];
}
return view;
}
}
Is there any delegate Method i´m missing?
please see the didSelectAnnotationView delegate method to your mapview.
example :
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
if([[view annotation] isKindOfClass:[myMarker class]]) return;
}
And here :
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if([[view annotation] isKindOfClass:[myMarker class]]) return nil;
}
In my app i am showing some place on map view using MKMapView . It was showing map fine. But from yesterday it is showing only grid and not showing the map , when i add delegate method it goes in the mapviewdidfiailtoload sometime.
I am using the below code
//mapview
myMapView=[[MKMapView alloc] initWithFrame:CGRectMake(0,gameNameLabel.frame.size.height, 320, 181)];
myMapView.mapType=MKMapTypeStandard;
myMapView.delegate=self;
LocationModel *loc=presentGame.location;
NSArray *cordinates=[loc.geoCordinates componentsSeparatedByString:#","];
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = [[cordinates objectAtIndex:0] doubleValue];
zoomLocation.longitude= [[cordinates objectAtIndex:1] doubleValue];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
// 3
MKCoordinateRegion adjustedRegion = [myMapView regionThatFits:viewRegion];
// 4
[myMapView setRegion:adjustedRegion animated:YES]; [scroll addSubview:myMapView];
Place *pin = [[Place alloc] init];
pin.name = loc.gameLocation;
pin.latitude = [[cordinates objectAtIndex:0] doubleValue];
pin.longitude = [[cordinates objectAtIndex:1] doubleValue];
PlaceMark* Place1 = [[PlaceMark alloc] initWithPlace:pin];
Place1.tagg=1;
[myMapView addAnnotation:Place1];
//end of mapview
- (MKAnnotationView *)mapView:(MKMapView *)mapView1 viewForAnnotation:(id )annotation {
static NSString *identifier = #"PlaceMark";
if ([annotation isKindOfClass:[PlaceMark class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView1 dequeueReusableAnnotationViewWithIdentifier:identifier];
annotationView.tag=[mapView1.annotations count];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
return annotationView;
}
return nil;
}
METERS_PER_MILE is defined as 1609.344
and i have set delegate in .h file .
All thing was working fine but now it showing the grid only , it showing Pin atleaset
I had the same problem MKMap View showing Only Grid not Showing Map View. I found out it was related to a change I made to the time/date on my mac. When I fixed the time and date to current time, the map worked again.
The iOS simulator comes with the official maps app included. Open that and verify that it can get tiles, it could be a network issue. If the Maps app isn't showing any tiles then you have network issues.
Can you try by turning off the animation by changing the line
[myMapView setRegion:adjustedRegion animated:YES];
By
[myMapView setRegion:adjustedRegion animated:NO];
I have the annotation ready to go, but trying to figure out on how to make it draggable with my code:
-(IBAction) updateLocation:(id)sender{
MKCoordinateRegion newRegion;
newRegion.center.latitude = mapView.userLocation.location.coordinate.latitude;
newRegion.center.longitude = mapView.userLocation.location.coordinate.longitude;
newRegion.span.latitudeDelta = 0.0004f;
newRegion.span.longitudeDelta = 0.0004f;
[mapView setRegion: newRegion animated: YES];
CLLocationCoordinate2D coordinate;
coordinate.latitude = mapView.userLocation.location.coordinate.latitude;
coordinate.longitude = mapView.userLocation.location.coordinate.longitude;
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate: coordinate];
[annotation setTitle: #"Your Car is parked here"];
[annotation setSubtitle: #"Come here for pepsi"];
[mapView addAnnotation: annotation];
[mapView setZoomEnabled: YES];
[mapView setScrollEnabled: YES];
}
Thanks in advance!
To make an annotation draggable, set the annotation view's draggable property to YES.
This is normally done in the viewForAnnotation delegate method.
For example:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *reuseId = #"pin";
MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (pav == nil)
{
pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
pav.draggable = YES;
pav.canShowCallout = YES;
}
else
{
pav.annotation = annotation;
}
return pav;
}
If you need to handle when the user stops dragging and drops the annotation, see:
how to manage drag and drop for MKAnnotationView on IOS?
In addition, your annotation object (the one that implements MKAnnotation) should have a settable coordinate property. You are using the MKPointAnnotation class which does implement setCoordinate so that part's already taken care of.
Progressing apace, trying to learn in and outs of MapKit and annotations.
I've made some good progress, but I'm having problems when I attempt to add location services to the mix.
If I return nil to the
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id < MKAnnotation >)annotation
method, I get a result VERY close to what I'm looking for, I have my annotation pins, I have my user's location showing in a standard way.
But if I return myPins (with all the parameters set as below), I get the correct behavior on all the pins but the properties are also set for the user's location (it's a red pin, it drops into place every time the view moves or a pin is selected). Annoying.
How does one set the properties for the annotations separately from the location? Is there a way to return multiple MKAnnotationViews? I know I'm missing some basic concept, but would appreciate any help you can give me. Thanks in advance.
Here's my main viewController, in total:
//
// ViewController.m
// mapFun
//
#import "ViewController.h"
#implementation ViewController
#synthesize segmentedControl;
#synthesize mapView,location, myLocations, myAnnotation, region;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
//location manager stuff
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if([CLLocationManager locationServicesEnabled])
{
[self.mapView setShowsUserLocation:YES];
[locationManager startUpdatingHeading];
}
[self loadUpLocations];
//set first zoom center and span, to zoom from to initial zoom
region.center=CLLocationCoordinate2DMake(
33.75070416856952,
-84.37034368515015);
MKCoordinateSpan span;
span.latitudeDelta=.3;
span.longitudeDelta=.3;
region.span=span;
[mapView setRegion:region animated:YES];
}
- (void)viewDidUnload
{
[self setMapView:nil];
[self setSegmentedControl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//zoom to initial zoom
[self setInitialZoom];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
//Load up a buncha locations
-(void)loadUpLocations{
myLocations = [LoadObjectsFromFile loadFromFile:#"locations2" ofType:#"plist"];
//loop through and make annotations
for (NSString *loc in myLocations) {
NSDictionary *value =[myLocations objectForKey:loc];
//create instance of MapAnnotations
CLLocationCoordinate2D temp =
CLLocationCoordinate2DMake(
[[value objectForKey:#"latitude"] doubleValue],
[[value objectForKey:#"longitude"] doubleValue]);
myAnnotation = [[MapAnnotations alloc]initWithLocation:temp];
myAnnotation.title = [value objectForKey:#"title"];
myAnnotation.subtitle = [value objectForKey:#"subtitle"];
myAnnotation.info =[value objectForKey:#"info"];
[self.mapView addAnnotation:myAnnotation];
}
}
- (void)setInitialZoom{
// MKCoordinateRegion region;
region.center = CLLocationCoordinate2DMake(33.77, -84.37);
//set level of zoom
MKCoordinateSpan span;
span.latitudeDelta=.04;
span.longitudeDelta=.04;
region.span=span;
[mapView setRegion:region animated:YES];
}
// used when selecting annotations
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
MKPointAnnotation *selectedAnnotation = view.annotation;
NSLog(#"The annotation selected is %#.",selectedAnnotation.title);
//set level of zoom
CLLocationCoordinate2D newCenter =
CLLocationCoordinate2DMake(
selectedAnnotation.coordinate.latitude,
selectedAnnotation.coordinate.longitude);
MKCoordinateSpan span;
span.latitudeDelta=.02;
span.longitudeDelta=.02;
MKCoordinateRegion zoomRegion = MKCoordinateRegionMake(newCenter, span);
[ self.mapView setRegion:zoomRegion animated:YES];
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
// [self zoomOutToInitial:nil];
}
- (IBAction)zoomOutToInitial:(id)sender {
[self.mapView setRegion:region animated:YES];
}
- (IBAction)segChanged:(id)sender {
if (self.segmentedControl.selectedSegmentIndex==0) {
[self.mapView setMapType:MKMapTypeStandard];
}
if (self.segmentedControl.selectedSegmentIndex==1) {
[self.mapView setMapType:MKMapTypeSatellite];
}
if (self.segmentedControl.selectedSegmentIndex==2) {
[self.mapView setMapType:MKMapTypeHybrid];
}
}
// This gets called every time an annotation is in the map view
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
NSLog(#"Map view can see annotation %#.",annotation.title);
MKPinAnnotationView *myPins;
if (!myPins) {
myPins= [[MKPinAnnotationView alloc]initWithAnnotation:self.myAnnotation
reuseIdentifier:#"myPins"];
}
myPins.animatesDrop = YES;
myPins.canShowCallout = YES;
myPins.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return nil;
//return myPins;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[manager stopUpdatingHeading];
}
#end
Answering my own question. Thanks anyway.
I finally found the answer in a useful document called "Location Awareness Programming Guide," from Apple.
Here's the corrected MKAnnotationView method:
// This gets called every time an annotation is in the map view
- (MKAnnotationView *)mapView:(MKMapView *)theView
viewForAnnotation:(id < MKAnnotation >)annotation
{
NSLog(#"Map view can see annotation %#.",annotation.title);
//if the annotation is a user location
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
//uses my custom class
if ([annotation isKindOfClass:[MapAnnotations class]]) {
// try for reuse of pins
MKPinAnnotationView *myPins = (MKPinAnnotationView *)
[theView dequeueReusableAnnotationViewWithIdentifier:#"myPins"];
if (!myPins) {
myPins= [[MKPinAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:#"myPins"];
myPins.animatesDrop = YES;
myPins.canShowCallout = YES;
myPins.rightCalloutAccessoryView =
[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}else
myPins.annotation = annotation;
return myPins;
}
return nil;
}
The basic concept is to return if and only if the view asked is actually the userlocation view.
You simply test if the Annotation forwarded to you is of userlocation class, like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// do your usual stuff
}
please i have recently made a Map which suppose to show the user location (green pin color) and others annotations for service stations (red pins color), for the moment, i am able to show all annotations with the same color and i still unable to tell the MKMapView delegate how to make difference between two pin types and so assign to each type the right title to show.
this is my MKAnnotationView method :
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [map dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
[annotationView setAnimatesDrop:YES];
annotationView.canShowCallout = YES;
return annotationView;
}
return nil;
}
and for my class which implement the MKAnnotation delegate i have this method :
-(id)initWithName:(NSString *)enseigneDeLaStation distanceVersLaStation:(NSString *) distanceVersLaStation coordinate:(CLLocationCoordinate2D)coordinate
{
if ((self = [super init])) {
_enseigneDeLaStation = [enseigneDeLaStation copy];
_distanceVersLaStation = [distanceVersLaStation copy];
_coordinate = coordinate;
}
return self;
}
thx in advance for your help :)
EDIT
i try to make the user location annotation like this, please if i am wrong correct me :
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
EDIT 2
Hi again, i try to make one annotation to make sure it even call the annotation method so imake this simple example :
latitudeOfUserLocation=43.2923;
longitudeOfUserLocation=5.45427;
location2D = (CLLocationCoordinate2D){ .latitude = latitudeOfUserLocation, .longitude = longitudeOfUserLocation };
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"coucou" coordinate:location2D]autorelease];
[mapView addAnnotation:annotation];
MKCoordinateSpan span={latitudeDelta:1,longitudeDelta:0.5};
MKCoordinateRegion region={location2D,span};
[mapView setRegion:region];
when i run the app, i see the region zoomed well which go with the 43.2923/5.45427 but i don't see the annotation, why it's not calling the annotation method,i can't move on since it's not showing the user annotation, please help, thx in advance :)
EDIT 3
Hi, i assumed that this has always relation with making difference between user and station pins, so i have declared a var codeColor, set it to 1 (the type of the user) when invoking the annotations and set it to 2(station type) when calling the annotations for the stations :
-(void)viewWillAppear:(BOOL)animated
{
codeColor=1;//it's the first type, the user one
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are right here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen;
[mapView addAnnotation:annotation];
}
and :
-(void)requestFinished:(ASIHTTPRequest *)request
{ codeColor=2;
[MBProgressHUD hideHUDForView:self.view animated:YES];
MyLocation *annotation=[[[MyLocation alloc]initWithName:ensStation distanceVersLaStation:distance coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorPurple;
[mapView addAnnotation:annotation];
}
and for the annotations method :
if (codeColor==2) {
annotationView.rightCalloutAccessoryView=[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
now when testing for the first time, all is ok, the user annotation without button and the station one is with the button, but when i move from the view and i came back, all annotations are with buttons, even the user one. could you please help me there, thx in advance :)
One simple way is to add a pinColor property to your MyLocation class:
#property (nonatomic, assign) MKPinAnnotationColor pinColor;
When creating the annotation, set the pinColor:
MyLocation *annotation=[[[MyLocation alloc]initWithName:#"You are here" distanceVersLaStation:#"" coordinate:location2D]autorelease];
annotation.pinColor = MKPinAnnotationColorGreen; //or red or whatever
[mapView addAnnotation:annotation];
and in the viewForAnnotation method:
//...
annotationView.canShowCallout = YES;
annotationView.pinColor = ((MyLocation *)annotation).pinColor;