The problem I'm working on is:
I have a MKMapKit and whenever a user taps on a building, street, the name pops up from the mapView, like so:
I have my own class AddressAnnotation, like so:
AddressAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface AddressAnnotation : NSObject <MKAnnotation>
- (id)initWithName:(NSString *)name address:(NSString *)address coordinate:(CLLocationCoordinate2D)coordinate;
#end
AddressAnnotation.m
#import "AddressAnnotation.h"
#import <AddressBook/AddressBook.h>
#interface AddressAnnotation()
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *address;
#property (nonatomic, assign) CLLocationCoordinate2D theCoordinate;
#end
#implementation AddressAnnotation
- (id)initWithName:(NSString*)name address:(NSString*)address coordinate:(CLLocationCoordinate2D)coordinate {
if ((self = [super init])) {
if ([name isKindOfClass:[NSString class]]) {
self.name = name;
} else {
self.name = #"";
}
self.address = address;
self.theCoordinate = coordinate;
}
return self;
}
- (NSString *)title {
return _name;
}
- (NSString *)subtitle {
return _address;
}
- (CLLocationCoordinate2D)coordinate {
return _theCoordinate;
}
And in my main MapViewController, I can specify a point and add a pin to that location, but that isn't what I want. I just want to be able to tap on a object and have their name pop up.
I couldn't find a question similar to this; please inform me if I've duplicated a question.
Thank you.
If you want a balloon to pop up above your annotation when you tap it. You use can MKMapViewDelegate in your controller.
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
// do this so you dont run the code for any other annotation type (eg blue dot for where your location is)
if([annotation isKindOfClass:[AddressAnnotation class]]){
MKPinAnnotationView* pv = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"spot"];
pv.pinColor = MKPinAnnotationColorPurple;
// decorate the balloon
UIImageView* iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"something.png"]];
iv.frame = CGRectMake(0, 0, 30, 30);
pv.leftCalloutAccessoryView = iv;
pv.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
// (default title and subtitle of the balloon will be taken from the annoation object)
// allow balloon to show when tapping
pv.canShowCallout = YES;
return pv;
}
return nil;
}
Related
I have written simple mapView application.It is showing two kind of problems.
1- Execution is stopping on Thread 1: signal SIGABRT error.
2- This function is showing compile time error .
- (IBAction)findMe:(id)sender {
If( [[toggleButton titleForState:UIControlStateNormal] isEqualToString:#"Find Me"] )
{
[toggleButton setTitle:#"Hide Me" forState:UIControlStateNormal];
mapView.showsUserLocation=YES;
}
else
{
[toggleButton setTitle:#"Find Me" forState:UIControlStateNormal];
mapView.showsUserLocation=NO;
}
}
How to remove these error ?
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
You can see the sample project from this link: https://drive.google.com/open?id=0B5pNDpbvZ8SnRmNFS0pjVnJFWHc
You are getting compile time error for 3 reasons:
1) The "If" you are using in if-else condition should be "if" i.e lowercase.
2). You have an IBOutlet connect to findMe button in storyboard which do not exist in your view controller. So either remove it or add it.
3)You are using MKMapView but you didn't added the MapKit Framework in "Link Binaries" in build phases option of your project.
Please do all these steps to have your code compiled & executed error free.
Answer to your query:
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
Here is the code for ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
#end
Here is the code for ViewController.m
#import "ViewController.h"
#import "MyAnnotation.h"
#import <MapKit/MapKit.h>
#interface ViewController ()
#property (strong, nonatomic) IBOutlet MKMapView *myMapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// setup the map view, delegate and current location
[self.myMapView setDelegate:self];
self.myMapView.mapType = MKMapTypeStandard;
CLLocationCoordinate2D myLocation = CLLocationCoordinate2DMake(25.085130,-77.331428);
[self.myMapView setCenterCoordinate:myLocation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(myLocation, 2000, 2000);
region.center = self.myMapView.centerCoordinate;
self.myMapView.showsUserLocation = YES;
[self.myMapView setRegion:region animated:YES];
[self dropPins];
}
-(void)dropPins {
NSMutableArray *annotationArray = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(25.085130, -77.331428);
MyAnnotation *annotation1 = [[MyAnnotation alloc] initWithCoordinates:location1 image:#"loc.png"];
[annotationArray addObject:annotation1];
[self.myMapView addAnnotations:annotationArray];
[annotationArray removeAllObjects];
CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(25.085130, -77.336428);
MyAnnotation *annotation2 = [[MyAnnotation alloc] initWithCoordinates:location2 image:#"loc.png"];
[annotationArray addObject:annotation2];
[self.myMapView addAnnotations:annotationArray];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyAnnotation class]])
{
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else
{
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin1.png"])
annotationView.image = [UIImage imageNamed:#"loc.png"];
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin2.png"])
annotationView.image = [UIImage imageNamed:#"loc.png"];
return annotationView;
}
return nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Add new files MyAnnotation.h/MyAnnotation.m
Here is the code for MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy, readonly) NSString *image;
-(id)initWithCoordinates:(CLLocationCoordinate2D) paramCoordinates
image:(NSString *) paramImage;
#end
Here is the code for MyAnnotation.m
#import "MyAnnotation.h"
#implementation MyAnnotation
-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
image:(NSString *)paramImage
{
self = [super init];
if(self != nil)
{
_coordinate = paramCoordinates;
_image = paramImage;
}
return (self);
}
#end
I'm using an array of Locations (stored online) which have a LocationID, lat, long, name, PinNumber and UserId.
Steps : I load the complete locations array of the selected user
I create pins with that array ( a simple for loop that uses the name, location, etc.)
Sadly, the MKPointAnnotation can only have a name and coordinates, and this is where my problems appears.
When my user selects a pin and uses the annotation (correct me if i'm wrong, that is the little info button inside the selected pin), he is redirected to another page where he can edit that location, and I can't find it in the database because i can't get the ID of the location.
I tried using NSInteger index = [mapView.annotations indexOfObject:view.annotation]; and check that index in my location array, but it just doesn't match.
What can i do to get my object back from that pin ? Or any workaround that gets the job done really.
You can subclass MKAnnotation and add your object ID to it as follows:
In CustomAnnotation.h,
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface CustomAnnotation : NSObject <MKAnnotation>
#property (nonatomic, retain) NSString *title;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSNumber *objectID;
- (id)initWithTitle:(NSString *)newTitle id:(NSNumber *)objectID location:(CLLocationCoordinate2D)location;
- (MKAnnotationView *)annotationView;
#end
In CustomAnnotation.m,
#import "CustomAnnotation.h"
#implementation CustomAnnotation
- (id)initWithTitle:(NSString *)newTitle id:(NSNumber *)objectID location:(CLLocationCoordinate2D)location
{
self = [super init];
if(self)
{
// Initialization code
_title = newTitle;
_coordinate = location;
_objectID = objectID;
}
return self;
}
- (MKAnnotationView *)annotationView
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"MyCustomAnnotation"];
// Your settings
annotationView.draggable = NO;
annotationView.enabled = YES;
return annotationView;
}
#end
Also, in mapView:viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// Customise all annotations except MKUserLocation
if([annotation isKindOfClass:[CustomAnnotation class]])
{
CustomAnnotation *point = (CustomAnnotation *)annotation;
MKAnnotationView *pointView = (MKAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnotation"];
if(pointView == nil)
pointView = point.annotationView;
else
pointView.annotation = annotation;
...
// do something with point.objectID
return pointView;
}
else
return nil;
}
You can subclass MKPointAnnotation and create a new property with your object
#interface CustomPointAnnotation : MKPointAnnotation
#property (nonatomic, strong) CustomObject* object;
#end
Now whenever you deal with an <MKAnnotation>, cast it to a CustomPointAnnotation* and set/get the object property.
I am trying to create draggable custom pin with Title popup with MapKit. but when I implement viewForAnnotation to make PIN appear as custom image, its disappears pop title as if I youch Pin on map it does not show titla popup,
while if I comments viewForAnnotation it works fine, but I want both things custom image and popup title when tap pin.
below is code
- (void)viewDidLoad
{
MKCoordinateRegion newRegion = MKCoordinateRegionMakeWithDistance(LocCoordinate, 20000, 20000);
DDAnnotation *point = [[DDAnnotation alloc] init];
[point setCoordinate:mapCenter];
[point setTitle:#"Where am I"];
[point setSubtitle:#"I am here"];
[self.mvTripMap addAnnotation:point];
[self.mvTripMap setRegion:newRegion animated:YES];
[super viewDidLoad];
}
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
}
return annotationView;
}
DDAnnotation.h
#import <MapKit/MapKit.h>
#interface DDAnnotation : MKPlacemark {
CLLocationCoordinate2D coordinate_;
NSString *title_;
NSString *subtitle_;
}
// Re-declare MKAnnotation's readonly property 'coordinate' to readwrite.
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#end
DDAnnotation.m
#import "DDAnnotation.h"
#implementation DDAnnotation
#synthesize coordinate = coordinate_;
#synthesize title = title_;
#synthesize subtitle = subtitle_;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary {
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary])) {
self.coordinate = coordinate;
}
return self;
}
#end
Just put annotationView.canShowCallout= YES; and it will work
updated code
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
annotationView.canShowCallout= YES;
}
return annotationView;
}
I would like to have a MKMapView showing annotations with disclosure-buttons which lead to a view controller like the Golden Gate Bridge annotation in this Apple sample app.
I load the coordinates from a plist and the annotations appear correctly with title/subtitle but the method
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
has no effect.
I guess that I somehow have to link the annotations with the pinannotations?
MapViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Annotation.h"
#interface MapViewController : UIViewController<CLLocationManagerDelegate, MKMapViewDelegate>
#property (strong, nonatomic) CLLocationManager *location;
#property (nonatomic, retain) NSArray *data;
#end
MapViewController.m:
#import "MapViewController.h"
#interface MapViewController ()
#property (nonatomic, weak) IBOutlet MKMapView *mapView;
#end
#implementation MapViewController
#synthesize data;
#synthesize location, minLatitude, maxLatitude, minLongitude, maxLongitude;
- (void)viewDidLoad
{
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"City" ofType:#"plist"];
self.data = [NSArray arrayWithContentsOfFile:dataPath];
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
//Create Annotation
Annotation *building = [[Annotation alloc] init];
building.title = [dataItem objectForKey:#"Title"];
building.subtitle = [dataItem objectForKey:#"Subtitle"];
MKCoordinateRegion buildingcoordinates = { {0.0, 0.0}, {0.0, 0.0} };
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
building.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:building];
}
[super viewDidLoad];
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *pinIdentifier = #"pinIndentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (pinView == nil)
{
// if an existing pin view was not available, create one
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
Annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#end
Annotation.m:
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle;
#end
Most likely the map view's delegate is not set which means the viewForAnnotation delegate method will not get called.
Since you've declared mapView as an IBOutlet, in the xib, make sure that the map view's delegate is connected to File's Owner.
Alternatively, at the top of the viewDidLoad method in MapViewController, set it programmatically:
mapView.delegate = self;
I have followed this tutorial:
http://www.shawngrimes.me/2011/04/custom-map-pins-for-mapkit/#comment-193
but I can't add a title and description
(see my code here http://pastebin.com/03mDLc9q)
You are trying to set name and description as properties of your annotation's view, you should be using title and subtitle on your annotation object - MyAnnotationClass, the annotation view will use title and subtitle of this object when the callout is rendered.
I changed your code to work here: http://pastebin.com/YRGYhQev
#interface MyAnnotationClass : NSObject<MKAnnotation>
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
-(id) initWithCoordinate:(CLLocationCoordinate2D) coordinate;
#end
MyAnnotationClass.m
#import "MyAnnotationClass.h"
#implementation MyAnnotationClass
-(id) initWithCoordinate:(CLLocationCoordinate2D) coordinate{
self=[super init];
if(self){
_coordinate = coordinate;
}
return self;
}
-(void) dealloc{
[_title release];
[_subtitle release];
[super dealloc];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController<MKMapViewDelegate> {
IBOutlet MKMapView *_myMapView;
NSArray *_myAnnotations;
}
#property (nonatomic, retain) NSArray *myAnnotations;
#property (nonatomic, retain) IBOutlet MKMapView *myMapView;
#end
ViewController.m
#import "ViewController.h"
#import "AppDelegate.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "PlaceMark.h"
#import "MyAnnotationClass.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize myMapView = _myMapView;
#synthesize myAnnotations = _myAnnotations;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void) viewDidLoad{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
//Initialize annotation
MyAnnotationClass *commuterLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake(appDelegate.latitude , appDelegate.longitude)];
commuterLotAnnotation.title = #"Hello title";
commuterLotAnnotation.subtitle = #"Correct";
MyAnnotationClass *overflowLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake(appDelegate.latitude , appDelegate.longitude)];
overflowLotAnnotation.title = #"Hello title";
overflowLotAnnotation.subtitle = #"Correct";
//Add them to array
self.myAnnotations=[NSArray arrayWithObjects:commuterLotAnnotation, overflowLotAnnotation, nil];
//Release the annotations now that they've been added to the array
[commuterLotAnnotation release];
[overflowLotAnnotation release];
//add array of annotations to map
[_myMapView addAnnotations:_myAnnotations];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
static NSString *parkingAnnotationIdentifier=#"ParkingAnnotationIdentifier";
if([annotation isKindOfClass:[MyAnnotationClass class]]){
//Try to get an unused annotation, similar to uitableviewcells
MKAnnotationView *annotationView=[_myMapView dequeueReusableAnnotationViewWithIdentifier:parkingAnnotationIdentifier];
//If one isn't available, create a new one
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:parkingAnnotationIdentifier];
//Here's where the magic happens
annotationView.image=[UIImage imageNamed:#"apple.gif"];
annotationView.canShowCallout = YES;
}
return annotationView;
}
return nil;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
I see that the tutorial has the MyAnnotationClass interface as:
#interface MyAnnotationClass : NSObject
When I used MKAnnotation I set my annotation interface up as:
#interface MyAnnotationClass : MKAnnotationView <MKAnnotation>
Then in the MyAnnotationClass.m file I have the following methods:
- (NSString *)title{
return self.name;
}
- (NSString *)subtitle{
return self.description;
}