About the Tab bar button with NSMutableArray annotation in MapKit - ios

I have created 4 type of annotation group. In the map UI, I also added a tab bar on the bottom as my button.
My tab bar is used to filter out the annotation in MapKit.
For example... I have 4 group of annotation and 4 tab bar item.
When I clicked tab bar item 1, it show only 1 group of annotation in MapKit, other group of annotation will hide/remove in MapKit but I failed to achieve this kind of work.
My code:
in MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface MapViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate , UITabBarDelegate>{
IBOutlet UITabBar *tabBar;
}
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
my mapViewController.m:
#import "MapViewController.h"
#import "SWRevealViewController.h"
#import "Annotation.h"
#interface MapViewController ()<CLLocationManagerDelegate>
#end
//set desitination of map
#define PENANG_LATI 5.419501;
#define PENANG_LONG 100.323264;
//shop
#define SHOP_LATI 5.419501;
#define SHOP_LONG 100.323264;
//cafe
#define CAFE_LATI 5.419917;
#define CAFE_LONG 100.322969;
//food
#define FOOD_LATI 5.419746;
#define FOOD_LONG 100.322610;
//mural
#define MURAL_LATI 5.419786;
#define MURAL_LONG 100.322510;
#define THE_SPAN 0.005f;
#implementation MapViewController
#synthesize mapView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//tabBar
tabBar.delegate = self;
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude = PENANG_LATI;
center.longitude = PENANG_LONG;
//SPAN
MKCoordinateSpan span;
span.latitudeDelta = THE_SPAN;
span.longitudeDelta = THE_SPAN;
myRegion.center = center;
myRegion.span = span;
//set map
[mapView setRegion:myRegion animated:YES];
SWRevealViewController *revealViewController = self.revealViewController;
if ( revealViewController )
{
[self.sidebarButton setTarget: self.revealViewController];
[self.sidebarButton setAction: #selector( revealToggle: )];
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
/*
//create coordinate
CLLocationCoordinate2D penangLocation;
penangLocation.latitude = PENANG_LATI;
penangLocation.longitude = PENANG_LONG;
Annotation * myAnnotation = [Annotation alloc];
myAnnotation.coordinate = penangLocation;
myAnnotation.title = #"THE ONE ACADEMY PENANG";
myAnnotation.subtitle = #"HELLO!! I STUDY HERE";
[self.mapView addAnnotation:myAnnotation];
*/
}
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
//my group of annotation location
NSMutableArray * myShop = [[NSMutableArray alloc] init];
NSMutableArray * myCafe = [[NSMutableArray alloc] init];
NSMutableArray * myFood = [[NSMutableArray alloc] init];
NSMutableArray * myMural = [[NSMutableArray alloc] init];
CLLocationCoordinate2D penangLocation;
Annotation * myShopAnnotation;
Annotation * myCafeAnnotation;
Annotation * myFoodAnnotation;
Annotation * myMuralAnnotation;
//shop location
myShopAnnotation = [[Annotation alloc] init];
penangLocation.latitude = SHOP_LATI;
penangLocation.longitude = SHOP_LONG;
myShopAnnotation.coordinate = penangLocation;
myShopAnnotation.title = #"Shop";
myShopAnnotation.subtitle = #"I study here";
[myShop addObject:myShopAnnotation];
//cafe location
myCafeAnnotation = [[Annotation alloc] init];
penangLocation.latitude = CAFE_LATI;
penangLocation.longitude = CAFE_LONG;
myCafeAnnotation.coordinate = penangLocation;
myCafeAnnotation.title = #"Cafe";
myCafeAnnotation.subtitle = #"I paid here";
[myCafe addObject:myCafeAnnotation];
//food location
myFoodAnnotation = [[Annotation alloc] init];
penangLocation.latitude = FOOD_LATI;
penangLocation.longitude = FOOD_LONG;
myFoodAnnotation.coordinate = penangLocation;
myFoodAnnotation.title = #"Food";
myFoodAnnotation.subtitle = #"I walk here";
[myFood addObject:myFoodAnnotation];
//Mural location
myMuralAnnotation = [[Annotation alloc] init];
penangLocation.latitude = MURAL_LATI;
penangLocation.longitude = MURAL_LONG;
myMuralAnnotation.coordinate = penangLocation;
myMuralAnnotation.title = #"Mural";
myMuralAnnotation.subtitle = #"I walk here";
[myMural addObject:myMuralAnnotation];
if(item.tag == 1)
{
//show and hide annotation
NSLog(#"shop");
[mapView addAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
}
if(item.tag == 2)
{
//show and hide annotation
NSLog(#"cafe");
[mapView removeAnnotations:myShop];
[mapView addAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
}
if(item.tag == 3)
{
//show and hide annotation
NSLog(#"food");
[mapView removeAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView addAnnotations:myMural];
}
if(item.tag == 4)
{
//show and hide annotation
NSLog(#"mural");
[mapView removeAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView addAnnotations:myMural];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

When removeAnnotations: is called like this:
[mapView removeAnnotations:myCafe];
the map view looks for the exact objects (using pointer comparison) in myCafe that are already on the map.
The map view here does not match up annotations using their coordinate, title, etc.
Since the code creates new instances of each annotation every time a selection is made, the new instances are not found on the map and so removeAnnotations: does nothing.
Instead, in your case, you could just tell the map view to remove all existing annotations and then add the new annotations based on the current selection.
Instead of this:
[mapView addAnnotations:myShop];
[mapView removeAnnotations:myCafe];
[mapView removeAnnotations:myFood];
[mapView removeAnnotations:myMural];
do this:
[mapView removeAnnotations:mapView.annotations]; //remove all
[mapView addAnnotations:myShop]; //then add new
The code could be simplified as well by using a switch statement and in each case, only create the annotations needed for the selection (you don't need to create all annotations every time).

Related

Open a new view using mapPin button Xcode

I am developing an app in Xcode (objective-c). My app has a TableView with a list of restaurants and when you press one row, another view is opened with the restaurant information. The method I am using is that I am sending the title in the row to the new view and depending on the title I load the information of the restaurant.
I want to do exactly the same using a map pin button. I have a map with pins and I want to press the right detail button an open another view with the restaurant information depending on the mapPin title.
Can someone help me! I was looking for tutorial and other posts but it doesn't work in my case. Thank you very much!
This is my MapViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController {
MKMapView *mapView;
}
#property (weak, nonatomic) IBOutlet UIBarButtonItem *barButton;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
-(IBAction)setMap:(id)sender;
#end
This is my MapViewController.m:
#import "MapViewController.h"
#import "SWRevealViewController.h"
#import "RestMapPin.h"
#import "RestViewController.h"
#interface MapViewController ()
#end
#implementation MapViewController
#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
_barButton.target = self.revealViewController;
_barButton.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
[self.navigationItem setTitle:NSLocalizedString (#"Map", nil)]; /*Cambia el titulo del navigation controller*/
[self.navigationController.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}]; /*Cambia el color de las letras del navigation controller bar del menu principal*/
[self.navigationController.navigationBar setBarTintColor:[UIColor colorWithRed:27/255.0f green:101/255.0f blue:163/255.0f alpha:1.0f]];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; /*Cambia el color del boton de la izquierda*/
mapView.delegate = self;
//1
//80 Grados
MKCoordinateRegion region_80_grados = { {0.0, 0.0}, {0.0, 0.0}};
region_80_grados.center.latitude = 40.42871179999999;
region_80_grados.center.longitude = -3.703639100000032;
region_80_grados.span.longitudeDelta = 0.1f;
region_80_grados.span.latitudeDelta = 0.1f;
[mapView setRegion:region_80_grados animated:YES];
RestMapPin *ann_80_grados = [[RestMapPin alloc] init];
ann_80_grados.title = #"80 Grados";
ann_80_grados.subtitle = #"Malasaña";
ann_80_grados.coordinate = region_80_grados.center;
[mapView addAnnotation:ann_80_grados];
//90 Grados
MKCoordinateRegion region_90_grados = { {0.0, 0.0}, {0.0, 0.0}};
region_90_grados.center.latitude = 40.4164161;
region_90_grados.center.longitude = -3.6699459999999817;
region_90_grados.span.longitudeDelta = 0.1f;
region_90_grados.span.latitudeDelta = 0.1f;
[mapView setRegion:region_90_grados animated:YES];
RestMapPin *ann_90_grados = [[RestMapPin alloc] init];
ann_90_grados.title = #"90 Grados";
ann_90_grados.subtitle = #"Retiro";
ann_90_grados.coordinate = region_90_grados.center;
[mapView addAnnotation:ann_90_grados];
/*B&B Babel*/
MKCoordinateRegion region_babel = { {0.0, 0.0}, {0.0, 0.0}};
region_babel.center.latitude = 40.4214535;
region_babel.center.longitude = -3.6974301;
region_babel.span.longitudeDelta = 0.1f;
region_babel.span.latitudeDelta = 0.1f;
[mapView setRegion:region_babel animated:YES];
RestMapPin *ann_babel = [[RestMapPin alloc] init];
ann_babel.title = #"B&B Babel";
ann_babel.subtitle = #"Barrio de Chueca";
ann_babel.coordinate = region_babel.center;
[mapView addAnnotation:ann_babel];
/*Babelia*/
MKCoordinateRegion region_Babelia = { {0.0, 0.0}, {0.0, 0.0}};
region_Babelia.center.latitude = 40.4234778;
region_Babelia.center.longitude = -3.686283000000003;
region_Babelia.span.longitudeDelta = 0.1f;
region_Babelia.span.latitudeDelta = 0.1f;
[mapView setRegion:region_Babelia animated:YES];
RestMapPin *ann_Babelia = [[RestMapPin alloc] init];
ann_Babelia.title = #"Babelia";
ann_Babelia.subtitle = #"Barrio de Salamanca";
ann_Babelia.coordinate = region_Babelia.center;
[mapView addAnnotation:ann_Babelia];
/*Bacira*/
MKCoordinateRegion region_Bacira = { {0.0, 0.0}, {0.0, 0.0}};
region_Bacira.center.latitude = 40.43375390000001;
region_Bacira.center.longitude = -3.699036299999989;
region_Bacira.span.longitudeDelta = 0.1f;
region_Bacira.span.latitudeDelta = 0.1f;
[mapView setRegion:region_Bacira animated:YES];
RestMapPin *ann_Bacira = [[RestMapPin alloc] init];
ann_Bacira.title = #"Bacira";
ann_Bacira.subtitle = #"Chamberí";
ann_Bacira.coordinate = region_Bacira.center;
[mapView addAnnotation:ann_Bacira];
/*Bar Galleta*/
MKCoordinateRegion region_bar_galleta = { {0.0, 0.0}, {0.0, 0.0}};
region_bar_galleta.center.latitude = 40.4227336;
region_bar_galleta.center.longitude = -3.7036699999999882;
region_bar_galleta.span.longitudeDelta = 0.1f;
region_bar_galleta.span.latitudeDelta = 0.1f;
[mapView setRegion:region_bar_galleta animated:YES];
RestMapPin *ann_bar_galleta = [[RestMapPin alloc] init];
ann_bar_galleta.title = #"Bar Galleta";
ann_bar_galleta.subtitle = #"Malasaña";
ann_bar_galleta.coordinate = region_bar_galleta.center;
[mapView addAnnotation:ann_bar_galleta];
/*Bar Tomate*/
MKCoordinateRegion region_bar_tomate = { {0.0, 0.0}, {0.0, 0.0}};
region_bar_tomate.center.latitude = 40.428041;
region_bar_tomate.center.longitude = -3.69047;
region_bar_tomate.span.longitudeDelta = 0.1f;
region_bar_tomate.span.latitudeDelta = 0.1f;
[mapView setRegion:region_bar_tomate animated:YES];
RestMapPin *ann_bar_tomate = [[RestMapPin alloc] init];
ann_bar_tomate.title = #"Bar Tomate";
ann_bar_tomate.subtitle = #"Chamberí";
ann_bar_tomate.coordinate = region_bar_tomate.center;
[mapView addAnnotation:ann_bar_tomate];
/*Indicador de posicion del mapa (para centrarlo)*/
MKCoordinateRegion region_posicion = { {0.0, 0.0}, {0.0, 0.0}};
region_posicion.center.latitude = 40.44934744420573;
region_posicion.center.longitude = -3.695504665374756;
region_posicion.span.longitudeDelta = 0.08f;
region_posicion.span.latitudeDelta = 0.08f;
[mapView setRegion:region_posicion animated:YES];
/*************************************************/
}
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != mapView.userLocation) {
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"pin2#2x.png"];
}
else {
//[mapView.userLocation setTitle:#"I am here"];
}
UIButton *pinButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[annotation title] isEqualToString:#"Bacira"]) {
}
pinView.rightCalloutAccessoryView = pinButton;
return pinView;
}
-(IBAction)setMap:(id)sender {
switch (((UISegmentedControl *) sender).selectedSegmentIndex) {
case 0:
mapView.mapType = MKMapTypeStandard;
break;
case 1:
mapView.mapType = MKMapTypeSatellite;
break;
case 2:
mapView.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is my RestMapPin.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface RestMapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
#end
And this is my RestMapPin.m:
#import "RestMapPin.h"
#implementation RestMapPin
#synthesize coordinate, title, subtitle;
#end
Finally this is the view where the information of the restaurants will appear: RestViewController.h:
#import <UIKit/UIKit.h>
#import "Restaurant.h"
#interface RestViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *TitleLabel;
#property (strong, nonatomic) IBOutlet UILabel *DescriptionLabel;
#property (strong, nonatomic) IBOutlet UIImageView *ImageView;
#property (nonatomic, strong) Restaurant *DetailModal;
#end
I konw that I have to modified my viewForAnnotation method but I don't know how to do it. Than you very much for your help!
Use this delegate method for right detail button
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
RestMapPin *annView = view.annotation;
YourViewController *objYourVC= [[YourViewController alloc]init];
objYourVC.title = annView.title;
objYourVC.subtitle = annView. subtitle;
[self.navigationController pushViewController:objYourVC animated:YES];
}
As the other poster said, use the map view delegate method mapView:viewCalloutAccessoryControlTapped:.
I would avise against using the title of the annotation to look up the restaurant though. You should not use display strings to index into your data. That means that if you change a display string, or localize for another language, your lookup no longer works.
I would add an ID field to your annotations and use that.
You need to do it like this
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
RestMapPin *selectedAnnotation = view.annotation;
NSLog("Title of selected pin - %#", selectedAnnotation.title);
// Here you get the title of selected annotation
}
Now after getting the title of your selected annotation you need to create the object of RestViewController and pass the title in the variable of that controller, Same as you are doing when user select any restaurant from list.
Also, as #Duncan C mentioned in his answer, you should not use String to get the data from server, Strings can be changed.

MKMapView: Issue with changing pin image

I am trying to change the standard pin to my own image but I keep failing after several attempts.
I have tried different codes and guides that I have found here in this forum but none of them seems to work. I belive I am pasting the code in to my project wrongly. Any ideas how to replace the regular pin with my own image?
//.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MapPin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *subtitle;
- (id)initWithLocation:(CLLocationCoordinate2D)coord;
#end
//.m
#import <Foundation/Foundation.h>
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate,title,subtitle;
- (id)initWithLocation:(CLLocationCoordinate2D)coord{
self = [super init];
if (self) {
coordinate = coord;
}
return self;
}
#end
//Viewcontroller.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface FirstViewController : UIViewController <UIAlertViewDelegate, UIWebViewDelegate> {
MKMapView *mapview;
}
- (IBAction)information;
#property (strong, nonatomic) IBOutlet UIScrollView *ScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (retain, nonatomic) IBOutlet MKMapView *mapview;
- (IBAction)showMenu;
- (IBAction)setMap:(id)sender;
- (IBAction)GetLocation:(id)sender;
#end
//Viewcontroller.m
#import "FirstViewController.h"
#import "MapPin.h"
#implementation FirstViewController
#synthesize ScrollView, image;
#synthesize mapview;
- (void)viewDidLoad{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[mapview addAnnotation:ann2];
ScrollView.scrollEnabled = YES;
[ScrollView setContentSize:CGSizeMake(320, 515)];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor= MKPinAnnotationColorGreen;
pinView.enabled = YES;
pinView.canShowCallout = YES;
pinView.image=[UIImage imageNamed:#"test.png"]; //here I am giving the image
return pinView;
}
See my other answer for working implementation.
Setting an IBOutlet delegate:
Since you're using an IBOutlet for your MKMapView you should control-drag from your MKMapView in your storyboard/xib file to the ViewController/"File's Owner" and select "delegate" from the popup.
Here a SO answer that covers creating custom pins: Custom pins
Also,
pinView.image=[UIImage imageNamed:#"test.png"];
should be
pinView.image=[UIImage imageNamed:#"test"];
Reference: Image from imageNamed:
The following worked for me:
Make sure MapKit.framework has been added to your project.
Make sure test.png is in your project (preferably in Images.xcassets)
Control-drag from your mapView in your storyboard to the ViewController and connect "delegate".
Then...
#import "MapPin.h"
#import <MapKit/MapKit.h>
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapview;
#end
#implementation ViewController
- (void)viewDidLoad
{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[self.mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[self.mapview addAnnotation:ann2];
}
- (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];
annotationView.image = [UIImage imageNamed:#"test"];
return annotationView;
}
}
#end
So I have followed the guidelines above, added the line of code and step3. Control-drag from your mapView in your storyboard to the ViewController and connect "delegate". which I named "pin".
But my image wont appear...I'll paste the new code again..there must be something wrong in it.
//Viewcontroller.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface FirstViewController : UIViewController <UIAlertViewDelegate, UIWebViewDelegate, MKMapViewDelegate> {
MKMapView *mapview;
}
- (IBAction)information;
#property (strong, nonatomic) IBOutlet UIScrollView *ScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *image;
#property (retain, nonatomic) IBOutlet MKMapView *mapview;
#property (strong, nonatomic) IBOutlet MKMapView *pin;
- (IBAction)showMenu;
- (IBAction)setMap:(id)sender;
- (IBAction)GetLocation:(id)sender;
#end
//Viewcontroller.m
#import "FirstViewController.h"
#import "MapPin.h"
#implementation FirstViewController
#synthesize ScrollView, image;
#synthesize mapview;
#synthesize pin;
- (void)viewDidLoad{
MKCoordinateRegion region = { {0.0, 0.0}, {0.0,0.0}};
region.center.latitude = 55.709900;
region.center.longitude = 13.201207;
region.span.longitudeDelta = 0.032f;
region.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region animated:YES];
MapPin *ann = [[MapPin alloc] init];
ann.title = #"test Town";
ann.subtitle = #"test Nation";
ann.coordinate = region.center;
ann.coordinate = region.center;
[self.mapview addAnnotation:ann];
MKCoordinateRegion region2 = { {0.0, 0.0}, {0.0,0.0}};
region2.center.latitude = 55.703904;
region2.center.longitude = 13.201207;
region2.span.longitudeDelta = 0.032f;
region2.span.latitudeDelta = 0.032f;
[self.mapview setRegion:region2 animated:YES];
MapPin *ann2 = [[MapPin alloc] init];
ann2.title = #"test Town";
ann2.subtitle = #"test Nation";
ann2.coordinate = region2.center;
ann2.coordinate = region2.center;
[self.mapview addAnnotation:ann2];
ScrollView.scrollEnabled = YES;
[ScrollView setContentSize:CGSizeMake(320, 515)];
}
- (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];
annotationView.image = [UIImage imageNamed:#"test"];
return annotationView;
}
}
#end

Add a marker to my map

I'm new to iOS, and it's so different from Android logic that I can't find how to add a marker to a map :-|
I've added a MKMapView to my xib
I've added this code to my .m (trimmed)
#import "AppDelegate.h"
#import <MapKit/MapKit.h>
#interface Dove ()
#property (weak,nonatomic) IBOutlet MKMapView *mappa;
#end
#define METERS_PER_MILE 1609.344
#implementation Dove
- (IBAction)vaiHome:(id)sender {
Index *second = [[Index alloc] initWithNibName:#"Index" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 45.40170;
zoomLocation.longitude= 8.91552;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, METERS_PER_MILE, METERS_PER_MILE);
[_mappa setRegion:viewRegion animated:YES];
[_mappa regionThatFits:viewRegion];
}
Now, how can I display a pin at that position? It should simple, but I can't find a solution :-|
Also, the map remain in united states but it most go to the marker.
Thanks a lot.
First you have to setup the annotation marker (call this in your viewdidload):
- (void)setupAnnotation
{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 45.40170;
zoomLocation.longitude= 8.91552;
NARMapViewAnnotation* annot = [[NARMapViewAnnotation alloc] initWithCoord:zoomLocation];
[_mapView addAnnotation:annot];
}
Then you have to setup the MKMapViewDelegate method:
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView* annotView = [views objectAtIndex:0];
id<MKAnnotation> mp = [annotView annotation];
MKCoordinateRegion region = [mv regionThatFits:MKCoordinateRegionMakeWithDistance([mp coordinate], REGION_WINDOW, REGION_WINDOW)];
[mv setRegion:region animated:YES];
}
NARMapViewAnnotation:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface NARMapViewAnnotation : NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
- (id)initWithCoord:(CLLocationCoordinate2D)coord;
#end
#import "NARMapViewAnnotation.h"
#implementation NARMapViewAnnotation
- (id)initWithCoord:(CLLocationCoordinate2D)coord
{
if (self = [super init])
{
_coordinate = coord;
}
return self;
}
#end

Using AVSpeechSynthesizer to read a description of location on a Map

My map has 4 or 5 points close to each other and right now using AVSpeechSynthesizer I've got it so that it will say the name of the location (which is also displayed in a little bubble).
I want it to still show that bubble but when clicked I want it to say a description of that place that I would have specified. This is my code at the moment:
MapViewAnnotation.h
#interface MapViewAnnotation : NSObject <MKAnnotation> {
NSString *title;
CLLocationCoordinate2D coordinate;
NSString *desc;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly) NSString *desc;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d initWithDesc:(NSString *)dsc;
MapViewAnnotation.m
#implementation MapViewAnnotation
#synthesize title, coordinate, desc;
- (id)initWithTitle:(NSString *)ttl andCoordinate:(CLLocationCoordinate2D)c2d initWithDesc:(NSString *)dsc {
[super init];
title = ttl;
coordinate = c2d;
desc = dsc;
return self;
MapViewController.h
#interface MapViewController : UIViewController {
MKMapView *mapView;
}
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property (strong, nonatomic) AVSpeechSynthesizer *synthesizer;
MapViewController.m
- (void)viewDidLoad
{
// Set some coordinates for our position : Cutty Sark
CLLocationCoordinate2D location;
location.latitude = (double) 51.482997;
location.longitude = (double) -0.010072;
// Royal Observatory
CLLocationCoordinate2D twoLocation;
twoLocation.latitude = (double) 51.477805;
twoLocation.longitude = (double) -0.001430;
//Royal Naval College
CLLocationCoordinate2D threeLocation;
threeLocation.latitude = (double) 51.483344;
threeLocation.longitude = (double) -0.006799;
//Queen's House
CLLocationCoordinate2D fourLocation;
fourLocation.latitude = (double) 51.481383;
fourLocation.longitude = (double) -0.003722;
//National Maritime Museum
CLLocationCoordinate2D fiveLocation;
fiveLocation.latitude = (double) 51.481050;
fiveLocation.longitude = (double) -0.005578;
// Add Cutty Sark annotation to MapView
MapViewAnnotation *newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Cutty Sark" andCoordinate:location initWithDesc:#"Description about Cutty Sark"];
[self.mapView addAnnotation:newAnnotation];
self.mapView.delegate = self;
[newAnnotation release];
// Add Royal Observatory annotation to MapView
newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Royal Observatory" andCoordinate:twoLocation initWithDesc:#"Description about Cutty Sark"];
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
// Add Royal Naval College annotation to MapView
newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Royal Naval College" andCoordinate:threeLocation initWithDesc:#"Description about Cutty Sark"];
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
// Add Queen's House annotation to MapView
newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"Queen's House" andCoordinate:fourLocation initWithDesc:#"Description about Cutty Sark"];
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
// Add National Maritime Museum annotation to MapView
newAnnotation = [[MapViewAnnotation alloc] initWithTitle:#"National Maritime Museum" andCoordinate:fiveLocation initWithDesc:#"Description about Cutty Sark"];
[self.mapView addAnnotation:newAnnotation];
[newAnnotation release];
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)anView
{
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc]init];
AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:((MapViewAnnotation *)anView).desc];
[utterance setRate:0.5];
[synthesizer speakUtterance:utterance];
}
// When a map annotation point is added, zoom to it (1500 range)
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 1500, 1500);
[mv setRegion:region animated:YES];
//[mv selectAnnotation:mp animated:YES];
}
Any help would be appreciated!
EDIT
Here is the NSLog:
In the didSelectAnnotationView delegate method, the anView parameter is the MKAnnotationView.
That is, anView is the view (MKAnnotationView or MKPinAnnotationView class) object of the annotation.
It is not the model (your MapViewAnnotation class) object of the annotation.
To refer to the annotation model instance that the view is for, use the view's annotation property and cast it to your class:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)anView
{
//Get a reference to the annotation this view is for...
id<MKAnnotation> annSelected = anView.annotation;
//Before casting, make sure this annotation is our custom type
//(and not some other type like MKUserLocation)...
if ([annSelected isKindOfClass:[MapViewAnnotation class]])
{
MapViewAnnotation *mva = (MapViewAnnotation *)annSelected;
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc]init];
AVSpeechUtterance *utterance =
[AVSpeechUtterance speechUtteranceWithString:mva.desc];
[utterance setRate:0.5];
[synthesizer speakUtterance:utterance];
}
}

Problems with MapView Pin Annotation - Pin loses color when map is zoomed/panned/region changes

I have a mapview that displays locations of cash points. Annotations are dropped and the callout can be clicked on to go to a page with more detail about that location. There are two categories of cashpoint, free and paid, free cashpoint pins are green and the other red. When the pins drop they are the correct colours. Everything works fine untill i zoom to user location or other areas of the map then when i go back to the pins they have lost their colour formatting and are all the original red colour.
I assume this is something to do with the map reloading when it downloads tiles and not reloading the pins properly, although i could be wrong.
Any help will be much appreciated.
here is my code:
#import "CashPointMapViewController.h"
#import "PinDrop.h"
#import "CashPointDetailViewController.h"
#implementation CashPointMapViewController
#synthesize app, theCashList, mapview, ann, count, myArray, pinColor;
- (IBAction) getlocation {
MKCoordinateRegion region;
region.center = self.mapview.userLocation.coordinate;
region.span.longitudeDelta = 0.01f;
region.span.longitudeDelta = 0.01f;
[mapview setRegion:region animated:YES];
}
- (void)viewDidLoad {
[super viewDidLoad];
mapview.showsUserLocation = YES;
[mapview setMapType:MKMapTypeStandard];
[mapview setZoomEnabled:YES];
[mapview setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, {0.0, 0.0 } };
region.center.latitude = 53.801279;
region.center.longitude = -1.548567;
region.span.longitudeDelta = 0.3f;
region.span.longitudeDelta = 0.3f;
[mapview setRegion:region animated:YES];
app = [[UIApplication sharedApplication]delegate];
UIImage *locate = [UIImage imageNamed:#"location arrow white.png"];
UIBarButtonItem *userlocatebutton = [[UIBarButtonItem alloc] initWithImage:locate style:UIBarButtonItemStylePlain target:self action:#selector(getlocation)];
self.navigationItem.rightBarButtonItem = userlocatebutton;
[self performSelectorInBackground:#selector(annloop) withObject:self];
}
-(void) annloop {
int i;
for (i=0; i<=count-1; i = i+1) {
theCashList = [myArray objectAtIndex:i];
NSString *trimlat = [theCashList.lat stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *trimlon = [theCashList.lon stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
double latdouble = [trimlat doubleValue];
double londouble = [trimlon doubleValue];
CLLocationCoordinate2D coord = {(latdouble),(londouble)};
ann = [[PinDrop alloc] init];
ann.index = i;
ann.title = [theCashList.name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *street = [theCashList.street stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *town = [theCashList.town stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *postcode = [theCashList.postcode stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *address = [[NSString alloc] initWithFormat:#"%#, %#, %#", street, town, postcode];
ann.subtitle = address;
ann.coordinate = coord;
NSString *trimprice = [theCashList.price stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([trimprice isEqualToString:#"Free"])
{
ann.price = 1;
}
else
{
ann.price = 0;
}
[mapview performSelectorOnMainThread:#selector(addAnnotation:) withObject:ann waitUntilDone:YES];
}
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]initWithAnnotation:ann reuseIdentifier:#"current"];
mypin.backgroundColor = [UIColor clearColor];
UIButton *goToDetail = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mypin.rightCalloutAccessoryView = goToDetail;
mypin.draggable = NO;
mypin.animatesDrop = TRUE;
mypin.canShowCallout = YES;
if (ann.price == 1)
{
mypin.pinColor = MKPinAnnotationColorGreen;
}
else
{
mypin.pinColor = MKPinAnnotationColorRed;
}
return mypin;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control {
PinDrop *annView = view.annotation;
CashPointDetailViewController *detailView = [[CashPointDetailViewController alloc]init];
theCashList = [myArray objectAtIndex:annView.index];
detailView.theCashList = theCashList;
[self.navigationController pushViewController:detailView animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
EDIT: Here is my .h if it helps.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "CashPointList.h"
#import <MapKit/MapKit.h>
#import "PinDrop.h"
#interface CashPointMapViewController : UIViewController {
MKMapView *mapview;
PinDrop *ann;
}
#property (nonatomic, retain) AppDelegate *app;
#property (nonatomic, retain) CashPointList *theCashList;
#property (nonatomic, retain) PinDrop *ann;
#property (nonatomic, retain) IBOutlet MKMapView *mapview;
#property (nonatomic, readwrite) int count;
#property (nonatomic, retain) NSMutableArray *myArray;
#property (nonatomic) MKPinAnnotationColor pinColor;
-(IBAction) getlocation;
#end
It's not a problem related to the map reloading tiles.
The issue is that the code in the viewForAnnotation delegate is using the ann object with the incorrect assumption that the class-instance-level ann object will be in sync with whenever the delegate method is called.
The viewForAnnotation delegate is not necessarily called in the order that you add annotations and can be called multiple times for the same annotation if the map needs to re-display an annotation when it comes back into view.
When the delegate method gets called again for a previously added annotation, ann and annotation no longer point to the same object. ann is now probably pointing to the last added annotation and so all the annotations change to its color.
In that delegate method, you must use the annotation parameter which is a reference to the annotation that the map view wants the view for in the current call (which may be completely unrelated to your outside loop).
So this line:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:ann reuseIdentifier:#"current"];
should be:
MKPinAnnotationView *mypin = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"current"];
^^^^^^^^^^
and when checking the annotation's properties, use the annotation parameter (and cast it to your custom class to get at the custom properties):
PinDrop *ann = (PinDrop *)annotation;
//Note that this local "ann" is NOT the same as the class-level "ann".
//May want to use a different name to avoid confusion.
//The compiler may also warn you about this.
if (ann.price == 1)
...
A separate, unrelated, but highly recommended suggestion is to implement annotation view re-use by using dequeueReusableAnnotationViewWithIdentifier. This will improve performance when you have lots of annotations.

Resources