iOS MapKit custom pins - ios

How do I show images instead of pins in the map. So far I can only add pins on tap. A sample code of the .m would extremely help since i'm still new to iOS programming.

#pragma mark -
#pragma mark MKMapView delegate
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKAnnotationView *annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:AnnotationIdentifier] autorelease];
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"someImage.png"];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(writeSomething:) forControlEvents:UIControlEventTouchUpInside];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
annotationView.rightCalloutAccessoryView = rightButton;
annotationView.canShowCallout = YES;
annotationView.draggable = YES;
return annotationView;
}
return nil;
}
EDIT:
I could explain to you all about the MKAnnotationView, but I think you will find the documentation provided by Apple to be a far better explanation than from any other source. Check the overview section in the link.
https://developer.apple.com/documentation/mapkit/mkannotationview

Go to organizer of Xcode and then go to documentation and search weatherMap it shows example for map with including images at annotation.

#pragma mark -
#pragma mark MKMapView delegate
-(void)addAllPinsOnMapView
{
MKCoordinateRegion region = mapViewOffer.region;
region.center = CLLocationCoordinate2DMake(12.9752297537231, 80.2313079833984);
region.span.longitudeDelta= 0.1f;
region.span.latitudeDelta= 0.1f;
[mapViewOffer setRegion:region animated:YES];
mapViewOffer.delegate=self;
arrMapPin=[[NSMutableArray alloc] init];
NSArray *name=[[NSArray alloc]initWithObjects:
#"Title1",
#"Title2",
#"Title3", nil];
NSMutableArray *arrCoordinateStr = [[NSMutableArray alloc] initWithCapacity:name.count];
[arrCoordinateStr addObject:#"12.970760345459,80.2190093994141"];
[arrCoordinateStr addObject:#"12.9752297537231,80.2313079833984"];
[arrCoordinateStr addObject:#"12.9788103103638,80.2412414550781"];
for(int i = 0; i < name.count; i++)
{
NSArray *components = [[arrCoordinateStr objectAtIndex:i] componentsSeparatedByString:#","];
double latitude = [components[0] doubleValue];
double longitude = [components[1] doubleValue];
MKPointAnnotation *mapPin = [[MKPointAnnotation alloc] init];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
mapPin.title = [name objectAtIndex:i];
mapPin.coordinate = coordinate;
[mapViewOffer addAnnotation:mapPin];
}
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:
(MKAnnotationView *)view
{
NSLog(#"%#",view.annotation.title);
NSLog(#"%f",view.annotation.coordinate.latitude);
NSLog(#"%f",view.annotation.coordinate.longitude);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(calloutTapped:)];
[view addGestureRecognizer:tapGesture];
}
-(void)calloutTapped:(UITapGestureRecognizer *) sender
{
NSLog(#"Callout was tapped");
MKAnnotationView *view = (MKAnnotationView*)sender.view;
id <MKAnnotation> annotation = [view annotation];
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
//[self performSegueWithIdentifier:#"annotationDetailSegue" sender:annotation];
OfferDetailsViewController *objOfferDetailsViewController = [[OfferDetailsViewController alloc]init];
[self.navigationController pushViewController:objOfferDetailsViewController animated:YES];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView
viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
static NSString *defaultPinID = #"annotationViewID";
pinView = (MKAnnotationView *)[mapViewOffer dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
}
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"placeholder"];
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[infoButton addTarget:self action:#selector(infoButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = infoButton;
return pinView;
}

Related

How to use different MKAnnotationView for 2 different MKPointAnnotation on the same MKMapView

I have 2 MKPointAnnotation and i want to display them on map with two different pins(MKAnnotationView having image).
// MKPointAnnotation - 1
CLLocationCoordinate2D cordinate;
cordinate.latitude = [_latitudeString doubleValue];
cordinate.longitude = [_longitudeString doubleValue];
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = CLLocationCoordinate2DMake(cordinate.latitude, cordinate.longitude);
[self.mapView addAnnotation:point1];
P.S - When i get second MKPointAnnotation i needed self zoom on that area.
// MKPointAnnotation - 2
CLLocationCoordinate2D cordinate;
cordinate.latitude = [_latStr doubleValue];
cordinate.longitude = [_longStr doubleValue];
MKPointAnnotation *point2 = [[MKPointAnnotation alloc] init];
point2.coordinate = CLLocationCoordinate2DMake(cordinate.latitude, cordinate.longitude);
[self.mapView addAnnotation:point2];
//This is my code for MKAnnotationView
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
What i need to change in the viewForAnnotation method?
For example, you can create subclass of MKPointAnnotation.
#interface SecondAnnotation: MKPointAnnotation
#end
#implementation SecondAnnotation
#end
Add SecondAnnotation to the mapView.
// MKPointAnnotation - 2
...
SecondAnnotation *point2 = [[SecondAnnotation alloc] init];
point2.coordinate = CLLocationCoordinate2DMake(cordinate.latitude,
cordinate.longitude);
[self.mapView addAnnotation:point2];
You can use different MKAnnotationView with the following code.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"Annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
} else if ([annotation isKindOfClass:[SecondAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"Second"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Writing the viewForAnnotation as below solved my problem -
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKPointAnnotation class]]){
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if(!pinView){
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
}
else{
pinView.annotation = annotation;
if ([annotation isKindOfClass:[SecondAnnotation class]]) {
pinView.image = [UIImage imageNamed:#"range"];
}
else{
pinView.image = [UIImage imageNamed:#"annotation"];
}
}
return pinView;
}
return nil;
}

How to add Tap gesture on MKPointAnnotation to show another view with data?

I have a an array of latitude and longitude and using for loop am displaying the MKPointAnnotation on the map. I want to show a view as a popup with data when the specific MKPointAnnotation is tapped.
Here is my code -
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 10000, 10000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
[_locationManager stopUpdatingLocation];
NSArray *set = [[NSArray alloc] init];
for (int i = 0; i < _json.count; i++) {
_name = [_json[i] valueForKey:#"name"];
_class = [_json[i] valueForKey:#"class"];
set = [_json[i] valueForKey:#"set"];
if (setFreeHour.count != 0) {
for (int j=0;j<set.count;j++) {
NSDictionary *dict = [[NSDictionary alloc] init];
dict = set[j];
_lat = dict[#"latitude"];
_longi = dict[#"longitude"];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [_lat doubleValue];
coordinate.longitude = [_longi doubleValue];
// Add an annotation
MKPointAnnotation *point1 = [[MKPointAnnotation alloc] init];
point1.coordinate = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude);
point1.title = _name;
point1.subtitle = _class;
[self.mapView addAnnotation:point1];
}
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView) {
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"annotation"];
pinView.calloutOffset = CGPointMake(0, 0);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showDetails)];
[pinView addGestureRecognizer:tap];
} else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
- (void)showDetails{
self.popup.hidden = NO;
}
//PS: popup is a view that contains labels. I want to pass data from MKPointAnnotation to the view
Why don't you use mapView(_:didSelect:) method instead of UITapGestureRecognizer?
(void)mapView:(MKMapView *)mapview didSelectAnnotationView:(MKAnnotationView *)view {
// 1. get data from view(MKAnnotationView)
// 2. pass data to another view
}
https://developer.apple.com/documentation/mapkit/mkmapviewdelegate/1452393-mapview

Add Pin Color to MKAnnotation

I have a button on Map which directs to "MyLocation" its hardcore lat n lng. i want to change the pin color. Tried some but not successful. Heres the code.
- (IBAction)btnMylLocation:(UIButton *)sender {
CLLocationCoordinate2D coord = {.latitude = 18.520430, .longitude = 73.856744};
MKCoordinateSpan span = {.latitudeDelta = 0.2, .longitudeDelta = 0.2};
MKCoordinateRegion region = {coord, span};
[self.mapView setRegion:region];
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = 18.520430;
annotationCoord.longitude = 73.856744;
self.lblLongitude.text = [NSString stringWithFormat:#"%f ", annotationCoord.latitude];
self.lblLatitude.text = [NSString stringWithFormat:#" %f", annotationCoord.longitude];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = #"Mindbowser";
annotationPoint.subtitle = #"Pune Headquater's";
[_mapView addAnnotation:annotationPoint];
}
You need to implement the map's delegate method and set the delegate.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
}
else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
In your viewDidLoad() , write the following code
_mapView.delegate = self;
This may help you.
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView *annotationView = nil;
if(![annotation isKindOfClass:[MKUserLocation class]]){
annotationView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"pin"];
annotationView.pinColor = MKPinAnnotationColorGreen;
}
return annotationView;
}
Implement the delegate method below and return MKAnnotationView by assigning the pinTintColor it is available from iOS 9.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *annotaionIdentifier=#"annotationIdentifier";
MKPinAnnotationView *aView=(MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:annotaionIdentifier ];
if (aView==nil) {
aView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:annotaionIdentifier];
aView.pinTintColor = [UIColor yellowColor];//from iOS 9, you can pass in any color you want.
//aView.pinColor = MKPinAnnotationColorPurple //if iOS is less than 9.0
aView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
aView.animatesDrop=TRUE;
aView.canShowCallout = YES;
aView.calloutOffset = CGPointMake(-5, 5);
}
return aView;
}
To change color while adding annotation, check below method.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation
(id<MKAnnotation>)annotation {
static NSString *identifier = #"PinAnnotationIdentifier";
MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(!pinAnnotation) {
pinAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
}
pinAnnotation.pinColor = MKPinAnnotationColorGreen; //Color
return pinAnnotation;
}
Use below method for changing color on select and deselect.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorRed;
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorGreen;
}

Adding action to MKMapView annotation

I have a MKMapView with a bunch of annotations but I can't add an action to them. I was just creating an MKPointAnnotation, but I couldn't add an action to that. Whenever I click the annotation, nothing happens. Here is how I am setting the annotations -
CLLocationCoordinate2D monteVista;
monteVista.latitude = (double) 37.83029;
monteVista.longitude = (double) -121.98827;
MKPointAnnotation *monteVistaPoint = [[MKPointAnnotation alloc] init];
monteVistaPoint.coordinate = monteVista;
monteVistaPoint.title = #"Monte Vista";
CLLocationCoordinate2D sanRamonValley;
sanRamonValley.latitude = (double) 37.82609;
sanRamonValley.longitude = (double) -122.00603;
MKPointAnnotation *sanRamonValleyPoint = [[MKPointAnnotation alloc] init];
sanRamonValleyPoint.coordinate = sanRamonValley;
sanRamonValleyPoint.title = #"San Ramon Valley";
CLLocationCoordinate2D doughertyValley;
doughertyValley.latitude = (double) 37.76845;
doughertyValley.longitude = (double) -121.90342;
MKPointAnnotation *doughertyValleyPoint = [[MKPointAnnotation alloc] init];
doughertyValleyPoint.coordinate = doughertyValley;
doughertyValleyPoint.title = #"Dougherty Valley";
NSArray *points = [[NSArray alloc] initWithObjects: monteVistaPoint, sanRamonValleyPoint, doughertyValleyPoint, nil];
[self.schoolMap addAnnotations:points];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
NSLog(#"Pin Created");
return annotationView;
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
MKPointAnnotation *testPoint = [[MKPointAnnotation alloc] init];
testPoint = view.annotation;
self.testText.text = testPoint.title;
NSLog(#"Selected");
}
You need to change viewForAnnotation: method in order customize and then just implement openDetail: action method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
{
return nil;
}
static NSString *identifier = #"CustomAnnotation";
MKAnnotationView* annView = nil;
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
annView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annView == nil) {
annView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annView.annotation = annotation;
}
UIImage *image = nil;
image = [UIImage imageNamed:#"pin2"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[annView addSubview:imageView];
[annView setFrame:CGRectMake(0, 0, imageView.frame.size.width, imageView.frame.size.height)];
// [annView setBackgroundColor:[UIColor colorWithRed:1 green:0 blue:0 alpha:0.1]];
UIButton*accessory = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[accessory setTag:[(CustomAnnotation*)annotation tag]];
[accessory addTarget:self action:#selector(openDetail:) forControlEvents:UIControlEventTouchUpInside];
[accessory setFrame:CGRectMake(0, 0, 30, 30)];
[annView setRightCalloutAccessoryView:accessory];
}
[annView setEnabled:YES];
[annView setCanShowCallout:YES];
return annView;
}

iOS distinguish between which callout accessory is tapped

In my map annotations, I have a UIButton as each accessory view in the callouts. In the - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control method, how do I figure out which accessory view was touched to handle each the events? Here's my code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
UIButton *calloutButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
UIButton *directionsButton = [UIButton buttonWithType:UIButtonTypeCustom];
directionsButton.frame = CGRectMake(0, 0, 23, 23);
[directionsButton setBackgroundImage:[UIImage imageNamed:#"directions.png"] forState:UIControlStateNormal];
MyPin.leftCalloutAccessoryView = directionsButton;
MyPin.rightCalloutAccessoryView = calloutButton;
MyPin.draggable = NO;
MyPin.highlighted = NO;
MyPin.animatesDrop= YES;
MyPin.canShowCallout = YES;
MyPin.pinColor = MKPinAnnotationColorRed;
return MyPin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
Annotation *ann = view.annotation;
if ([control tag] == 1) {
CLLocationCoordinate2D currentCoords = {ann.coordinate.latitude, ann.coordinate.longitude};
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate: currentCoords addressDictionary:nil];
MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark: place];
destination.name = ann.title;
destination.url = [NSURL URLWithString:#"http://www.wccca.com/PITS"];
NSArray *items = [[NSArray alloc] initWithObjects: destination, nil];
NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsDirectionsModeKey, nil];
[MKMapItem openMapsWithItems: items launchOptions: options];
}
if ([control tag] == 2) {
MKCoordinateRegion region;
region.center.latitude = ann.coordinate.latitude;
region.center.longitude = ann.coordinate.longitude;
region.span.latitudeDelta = 0.02;
region.span.longitudeDelta = 0.02;
[self.mapView setRegion:region animated:YES];
}
}
Rather than setting and using tags, you could just check if control is the left or right accessory view:
if (control == view.leftCalloutAccessoryView) {
//handle left control tap...
}
else
if (control == view.rightCalloutAccessoryView) {
//handle right control tap...
}

Resources