Is it possible?
Im performing an action here that gives to me a pin. But i need a image. And MKAnnotation seems complicated for me.
- (void)abreMapa:(NSString *)endereco {
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv",
[endereco stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString]];
NSArray *listItems = [locationString componentsSeparatedByString:#","];
double latitude = 0.0;
double longitude = 0.0;
if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:#"200"]) {
latitude = [[listItems objectAtIndex:2] doubleValue];
longitude = [[listItems objectAtIndex:3] doubleValue];
}
else {
//Show error
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude;
coordinate.longitude = longitude;
myMap.region = MKCoordinateRegionMakeWithDistance(coordinate, 2000, 2000);
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:coordinate];
[annotation setTitle:#"Some Title"];
[myMap addAnnotation:annotation];
// Coloca o icone
[self.view addSubview:mapa];
}
Thanks!
You'll need to set up an MKMapViewDelegate, and implement
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
Here's sample code, stolen from the MapCallouts sample code provided on Apple's developer site. I've modified it to focus on the important details. You can see below that the key is to set the image on an annotation view, and return that annotation view from this method.
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *SFAnnotationIdentifier = #"SFAnnotationIdentifier";
MKPinAnnotationView *pinView =
(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
if (!pinView)
{
MKAnnotationView *annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:SFAnnotationIdentifier] autorelease];
UIImage *flagImage = [UIImage imageNamed:#"flag.png"];
// You may need to resize the image here.
annotationView.image = flagImage;
return annotationView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
We use dequeueReusableAnnotationViewWithIdentifier to grab an already created view to make reuse of our annotation views. If one isn't returned we create a new one. This prevents us from creating hundreds of MKAnnotationViews if only a few are ever in sight at the same time.
Related
I create one app that have mapkit and I can to add specific annotations in my map and I want when to tap (click) on any annotation do one method or one action but I don't about it.
please guide me . I searching many time in google but don't give correct answer for my question.
this is my code :
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
locationManager = [[CLLocationManager alloc] init];
[self GetMyLocation];
mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0, 0, 320, 500)];
mapView.mapType = MKMapTypeStandard;
mapView.zoomEnabled = YES;
mapView.scrollEnabled = YES;
mapView.showsUserLocation = YES;
[mapView.userLocation setTitle:#"I'm Here"];
[mapView.userLocation setSubtitle:#"Rahnova Corpration"];
[self.view addSubview:mapView];
[self addAnnonations];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGesture:)];
[self.mapView addGestureRecognizer:longPressGesture];
}
- (void) addAnnonations{
NSArray *title = [[NSArray alloc]initWithObjects:#"Rome",#"Chelsea", nil];
NSArray *subtitle = [[NSArray alloc]initWithObjects:#"Red",#"Blue", nil];
NSArray *latitude = [[NSArray alloc]initWithObjects:#"35.738000",#"35.739901", nil];
NSArray *longitude = [[NSArray alloc]initWithObjects:#"51.310029",#"51.312018", nil];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
[dictionary setObject:title forKey:#"title"];
[dictionary setObject:subtitle forKey:#"subtitle"];
[dictionary setObject:latitude forKey:#"latitude"];
[dictionary setObject:longitude forKey:#"longitude"];
for (int i = 0; i <= 1; i++) {
NSString *Name = [[dictionary objectForKey:#"title"]objectAtIndex:i];
NSString *SubName = [[dictionary objectForKey:#"subtitle"]objectAtIndex:i];
double Lati = [[[dictionary objectForKey:#"latitude"]objectAtIndex:i] doubleValue];
double Long = [[[dictionary objectForKey:#"longitude"]objectAtIndex:i] doubleValue];
[self SetTitle:Name SetSubtitle:SubName SetLatitude:Lati SetLongitude:Long];
}
}
- (void) SetTitle:(NSString *)title SetSubtitle:(NSString *)subtitle SetLatitude:(double)latitude SetLongitude:(double)longitude{
//create coordinate for use annotation
CLLocationCoordinate2D annoLocation;
annoLocation.latitude = latitude;
annoLocation.longitude = longitude;
Annotation *myAnnonation = [[Annotation alloc]init];
myAnnonation.coordinate = annoLocation;
myAnnonation.title = title;
myAnnonation.subtitle = subtitle;
[self.mapView addAnnotation:myAnnonation];
}
- (void) centerLocation{
//create region
MKCoordinateRegion myRegion;
CLLocationCoordinate2D center;
center.latitude = latitudes;
center.longitude = longitudes;
//span
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;
myRegion.center = center;
myRegion.span = span;
[mapView setRegion:myRegion animated:YES];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudes = currentLocation.coordinate.longitude;
latitudes = currentLocation.coordinate.latitude;
[self centerLocation];
}
}
#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
dude try this :
Xcode 4 iPhone SDK Tutorial - How to add different actions to each annotation-pin HD
or this :
Detecting when MKAnnotation is selected in MKMapView
Ok so I am making an iOS application using the MapKit framework. I have got the functionality working but am now having trouble when changing the icon of the annotation. I can change the annotations icon but when I do so the annotation looses it's title and subtitle values (nothing pops up when tapped). I think maybe the issue is due to something like not giving the annotation an identifier when first made but I am not sure...
If anyone could let me know whats going on it would be greatly appreciated!
The code to add annotation is:
-(void)addAnnotationAtLattitude:(double)lattitude withLongitude:(double)longitude withTitle:(NSString *)title withSubtitle:(NSString *)subtitle{
//Handles the adding off the anotation
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = lattitude;
annotationCoord.longitude = longitude;
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = title;
annotationPoint.subtitle = subtitle;
[self.MessageMap addAnnotation:annotationPoint];
}
and the code to change the icon (via delegate method ) is:
-(MKAnnotationView *)mapView:(MKMapView *)_mapView viewForAnnotation:(id
<MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationViewID];
}
annotationView.image = [UIImage imageNamed:#"CustomMapAnnotationIcon"];//mycustom image
annotationView.annotation = annotation;
return annotationView;
}
Are annotationView.enabled and annotationView.canShowCallout set to YES?
In my viewcontroller I use Maps and I load a list of pins.
When I move the map or zoom in or out it, my app crashes and displays this error:
[GMMGeoTileImageData isEqualToString:]: unrecognized selector sent to instance 0x862d3b0
This is my code of the view controller:
- (void)viewDidLoad
{
statoAnn = [[NSMutableString alloc] initWithFormat:#"false"];
//bottone annulla per tornare indietro
UIBarButtonItem *annullaButton = [[[UIBarButtonItem alloc] initWithTitle:#"Annulla" style:UIBarButtonItemStylePlain target:self action:#selector(backView)] autorelease];
self.navigationItem.leftBarButtonItem = annullaButton;
//inizializzo la mappa
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 416)];
mapView.delegate = self;
mapView.mapType = MKMapTypeStandard;
[self.view addSubview:mapView];
[self setGmaps:arrData];
[super viewDidLoad];
}
/** inizializzo l'annotation del poi mappa **/
- (void) setGmaps:(NSMutableArray*)inputData {
// setto la lat e lng
CLLocationDegrees latitude;
CLLocationDegrees longitude;
CLLocationCoordinate2D poiLocation;
arrAnn = [[NSMutableArray alloc] init];
for(int i=0; i<[inputData count]; i++) {
//ricavo la lat e lng del pin
latitude = [[[inputData objectAtIndex:i] objectForKey:#"latitude"] doubleValue];
longitude = [[[inputData objectAtIndex:i] objectForKey:#"longitude"] doubleValue];
// setto la location del poi
poiLocation.latitude = latitude;
poiLocation.longitude = longitude;
//[[[CLLocation alloc] initWithLatitude:latitude longitude:longitude] autorelease];
//setto il pin
Annotation *ann = [[Annotation alloc] initWithCoordinate:poiLocation];
ann.title = [[inputData objectAtIndex:i] objectForKey:#"label"];
[arrAnn addObject:ann];
[ann release];
}
if (nil != self.arrAnn) {
[self.mapView addAnnotations:arrAnn];
//self.ann = nil;
self.arrAnn = nil;
}
}
/** setto il pin nella mappa ***/
- (void)setCurrentLocation:(CLLocation *)location {
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center = location.coordinate;
region.span.longitudeDelta = 0.1f;
region.span.latitudeDelta = 0.1f;
[self.mapView setRegion:region animated:YES];
[self.mapView regionThatFits:region];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapViewTemp viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *view = nil; // return nil for the current user location
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"identifier"];
if (nil == view) {
view = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"identifier"] autorelease];
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
[view setPinColor:MKPinAnnotationColorPurple];
[view setCanShowCallout:YES];
[view setAnimatesDrop:YES];
if (![statoAnn isEqualToString:#"true"]) {
CLLocation *location = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude
longitude:annotation.coordinate.longitude];
[self setCurrentLocation:location];
statoAnn = [NSMutableString stringWithFormat:#"true"];
}
return view;
}
In viewForAnnotation, this line:
statoAnn = [NSMutableString stringWithFormat:#"true"];
sets statoAnn to an autoreleased string.
When the method exits, release is called on statoAnn and it no longer owns the memory it was pointing to. When the method is called again when you zoom or move the map, the memory that statoAnn was pointing to is now used by something else (GMMGeoTileImageData in this case). That object is not an NSString and doesn't have an isEqualToString: method and you get the error you are seeing.
To fix this, set statoAnn so the value is retained like you are doing in viewDidLoad. For example, you could change it to:
statoAnn = [[NSMutableString alloc] initWithFormat:#"true"];
You could also declare statoAnn as a property (#property (nonatomic, copy) NSString *statoAnn) and just set it using self.statoAnn = #"true";. The property setter will do the retaining for you.
However, you don't need to use a string to hold a "true" and "false" value. It's much easier and efficient to use a plain BOOL and you won't have to worry about retain/release since it's a primitive type and not an object.
The other thing is that viewForAnnotation is not the right place to be setting the map view's region in the first place. You can do that in viewDidLoad after the annotations are added.
Another thing: At the top of viewForAnnotation, you have the comment "return nil for the current user location" but that code doesn't do that. It just initializes the view to nil. To actually do what the comment says, you need this:
MKPinAnnotationView *view = nil;
// return nil for the current user location...
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
Finally, if the dequeueReusableAnnotationViewWithIdentifier does return a view (if view != nil), you need to set view.annotation to the current annotation since the re-used view may have been for a different annotation.
I have more than 2800 locations to be put on my map.
But when i am putting them the map is freezing. i can do nothing but wait until all the annotation data is available.
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
NSAutoreleasePool *pool_mr = [[NSAutoreleasePool alloc] init];
NSLog(#"mapView:regionDidChangeAnimated:");
NSLog(#"latitude: %f, longitude: %f", regionsMapView.centerCoordinate.latitude, regionsMapView.centerCoordinate.longitude);
NSLog(#"latitudeDelta: %f, longitudeDelta: %f", regionsMapView.region.span.latitudeDelta, regionsMapView.region.span.longitudeDelta);
if (regionsMapView.region.span.latitudeDelta < 0.007) {
NSLog(#"SHOW ANNOTATIONS");
NSArray *annotations = [regionsMapView annotations];
AddressAnnotation *annotation = nil;
for (int i=0; i<[annotations count]; i++)
{
NSLog(#"%i", i);
annotation = (AddressAnnotation*)[annotations objectAtIndex:i];
[[regionsMapView viewForAnnotation:annotation] setHidden:NO];
}
}else {
NSLog(#"HIDE ANNOTATIONS");
NSArray *annotations = [regionsMapView annotations];
AddressAnnotation *annotation = nil;
for (int i=0; i<[annotations count]; i++)
{
NSLog(#"%i", i);
annotation = (AddressAnnotation*)[annotations objectAtIndex:i];
[[regionsMapView viewForAnnotation:annotation] setHidden:YES];
}
}
[pool_mr release];
}
And the Another method is like below:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation, AddressAnnotation>) annotation {
//NSAutoreleasePool *pool5 = [[NSAutoreleasePool alloc] init];
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]]){
NSLog(#"MKUserLocation");
return nil;
}
else {
NSLog(#"mapView:viewForAnnotation>>>");
NSLog(#"%#", [annotation markerColor]);
NSLog(#"image: %#", [NSMutableString stringWithFormat:#"MKPinAnnotationView_%#.png",[annotation markerColor]]);
MKPinAnnotationView *annView=[[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:[annotation markerColor]] autorelease];
//annView.pinColor = MKPinAnnotationColorPurple;
UIImage *annotationImage = [[UIImage imageNamed:[NSMutableString stringWithFormat:#"MKPinAnnotationView_%#.png",[annotation markerColor]]] autorelease];
annView.image = annotationImage;
annView.animatesDrop = NO;
annView.canShowCallout = YES;
//annView.draggable = NO;
//annView.highlighted = NO;
annView.calloutOffset = CGPointMake(-5, 5);
return annView;
}
//[pool5 release];
NSLog(#"<<<mapView:viewForAnnotation");
return nil;
}
With that number of annotations, I would cluster them so as you zoom in, you get more detail. I put several thousand on a map that way and it works a treat. There is lots of information about map pin clustering if you search for it.
Here's one commercial option for example (no connection, haven't used) but if you look around you'll see plenty of information on how to implement it yourself.
I am trying to remove all the annotations of a map. The class that contains the MKMapView implements the MKMapViewDelegate. I am calling the remove all annotations method when a button (displayed in a modal view) is clicked. I am using the next code to remove all the annotations.
- (void)removeAllAnnotations {
NSMutableArray *annotationsToRemove = [NSMutableArray arrayWithCapacity:[self.mapView.annotations count]];
for (int i = 0; i < [self.mapView.annotations count]; i++) {
if ([[self.mapView.annotations objectAtIndex:i] isKindOfClass:[AddressAnnotation class]]) {
[annotationsToRemove addObject:[self.mapView.annotations objectAtIndex:i]];
}
}
[self.mapView removeAnnotations:annotationsToRemove];
}
The code works right but after calling the method, and when I try to add new annotations to the empty map, the class does not call to the viewForAnnotations method and the annotations do not drop down and do not show a disclosure button into the annotation view. Why is this happening?
Thanks for reading.
Edited:
The annotations are shown but with out calling the view for annotation method (with out dropping down and with out including a disclosure button into the annotation view). Here is the method that I use to add the annotations and the viewForAnnotation method.
- (void)loadAnnotations:(NSString *)type {
NSString *path = [[NSBundle mainBundle] pathForResource:#"PlacesInformation" ofType:#"plist"];
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
for (int i = 0; i < tmpArray.count; i++) {
// Breaks the string down even further to latitude and longitude fields.
NSString *coordinateString = [[tmpArray objectAtIndex:i] objectForKey:#"coordinates"];
NSString *option = [[tmpArray objectAtIndex:i] objectForKey:#"type"];
if ([option isEqualToString:type]) {
CLLocationCoordinate2D currentCoordinate = [self stringToCoordinate:coordinateString];
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:currentCoordinate] autorelease];
[self.mapView addAnnotation:annotation];
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
else { // Handles the other annotations.
// Try to dequeue an existing pin view first.
static NSString *AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView) {
// If an existing pin view was not available, creates one.
MKPinAnnotationView *customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// Adds a detail disclosure button.
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
} else
pinView.annotation = annotation;
}
return nil;
}
In viewForAnnotation, in the case where you are reusing a view, you are currently returning nil.
This else part:
} else
pinView.annotation = annotation;
Should probably be:
} else {
pinView.annotation = annotation;
return pinView;
}