Hide annotation subtitle, or change color - iphone

In my app am adding subtitle to annotation pin but don't want to show with pin. I am just using it for coding purpose. How can I hide or change subtitle color?

If I understand your question correctly, you are using pin subtitle for some processing and doesn't want to show it on pin. If you are using default callout then it is not possible to change colour of subtitle or to hid it once you assign annotation.subtitle = #"some subtitle".
I would suggest, add another variable to annotation and assign subtitle to that variable (annotation.newSubtitle = #"some subtitle")and don't assign anything for subtitle attribute. All the processing you want to do then can be done with annotation.newSubtitle.
If you are reluctant to add new variable to annotation then you will have to implement custom callout which is tedious.
EDIT:
You will find following useful to assign NSString to your annotation.
#interface MyAnnotation : NSObject<MKAnnotation> {
NSString *newSubTitle;
}
#property(retain,readwrite, nonatomic) NSString *newSubTitle ;
#end
In implementation part
#implementation MyAnnotation
#synthesize mSubTitle;
-(void)setNewSubTitle:(NSString *)SubTitle{
self.newSubTitle = SubTitle;
}
#end
And for assigning
[annotation setNewSubTitle: #"some text"];
for accessing
myString = annotation.newSubtitle

If you want access any string for every specific annotation, you can use NSMutableDictionary and add your annotation as key. and later you could access this in
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {

Related

iOS - How to use mkmapview as location picker

In my app I have two address UITextfields to be filled up using address text. I want this behavior:
As soon as user enters address textfield, a map appears from down. (already done)
User plays with the map. As he does that, a floating annotation object appears which is just about to drop.
A button (a subview of mkmapview), when pressed, drops this floating annotation on to the map.
As soon as user presses Done button, the annotation location on the map is reverse-geocoded.
The map view disappears (already done).
The UITextfield is populated with address text corresponding to center of the map view.
Same is repeated for another UITextfield.
I believe this is a very straight use case of mkmapview. But can't find any examples of this already done.
Am I missing something pretty obvious in UIKit?
Many thanks for your help....
EDIT:
I read up Apple's docs, and I found many solutions that point towards this.
However all of them seems to assume that MKPinAnnotationView (or MKAnnotationView) is overridden.
Is it necessary?
If yes, how much I need to provide in the subclass apart from dragging?
No need to subclass MKPinAnnotationView. Just use it. You only should be subclass it if you're looking for some custom behavior. But it is useful to write a viewForAnnotation so you can configure it properly. But typically I find the configuration of a standard MKPinAnnotationView to be simple enough that no subclassing is needed:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"DroppedPin"];
annotationView.draggable = YES;
annotationView.canShowCallout = YES;
annotationView.animatesDrop = YES;
return annotationView;
}
Having said that, it is not uncommon to have your own annotation class. I might do this for at least two reasons:
You might keep the reverse geocoded MKPlacemark as a property of your annotation. Logically, the geocoded information seems like a property of the annotation, not of the view. You can then inquire this placemark property of the dropped pin to get whatever information you need to pass back to your other view.
If you want, you could configure your annotation to both perform the reverse geocode lookup which would the placemark property, but also change the title to the reverse geocoded address when you change its coordinate, too. This way, the user is getting active feedback about what the reverse geocoding as they're dragging and dropping the pin on the map, but the code is still super simple:
Thus, you might have an annotation class like:
#interface DroppedAnnotation : NSObject <MKAnnotation>
#property (nonatomic, strong) MKPlacemark *placemark;
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *subtitle;
#end
#implementation DroppedAnnotation
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate
{
CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude
longitude:coordinate.longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
// do whatever you want here ... I'm just grabbing the first placemark
if ([placemarks count] > 0 && error == nil)
{
self.placemark = placemarks[0];
NSArray *formattedAddressLines = self.placemark.addressDictionary[#"FormattedAddressLines"];
self.title = [formattedAddressLines componentsJoinedByString:#", "];
}
}];
_coordinate = coordinate;
}
#end
And your view controller can use this new class:
#property (nonatomic, weak) id<MKAnnotation> droppedAnnotation;
- (void)dropPin
{
// if we've already dropped a pin, remove it
if (self.droppedAnnotation)
[self.mapView removeAnnotation:self.droppedAnnotation];
// create new dropped pin
DroppedAnnotation *annotation = [[DroppedAnnotation alloc] init];
annotation.coordinate = self.mapView.centerCoordinate;
annotation.title = #"Dropped pin"; // initialize the title
[self.mapView addAnnotation:annotation];
self.droppedAnnotation = annotation;
}
To be clear, you don't need your own annotation class. You could use the standard MKPointAnnotation for example. But then your view controller has to keep call and keep track of reverse geocoded information itself. I just think the code is a little cleaner and more logical when you use a custom annotation class.

iphone: How to show different image for every pin point on MapKit?

I want to put Start and End image with overlay in an iPhone/iPad application. I have start and end Lattitude and Longitude values and want to draw overlay between start and end points and put start image on Start point and End Image on End point.
I have googled but What I found is MapKit gets one image and set it on both Start and End points, could not find any help for 2nd image.
like
annotationView.image=[UIImage imageNamed:#"parkingIcon.png"];
It only set one image for both start and end points. But I want to put different images for both points.
Please help.
I got that ... thanks for all who tried to help me out. the Complete solution is
Create a class
#interface MyAnnotationClass : NSObject <MKAnnotation> {
NSString *_name;
NSString *_description;
CLLocationCoordinate2D _coordinate;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
-(id) initWithCoordinate:(CLLocationCoordinate2D) coordinate;
ViewDidLoad method code :
mapView.delegate = self;
//Initialize annotation
MyAnnotationClass *commuterLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake( 39.047752, -76.850388)];
commuterLotAnnotation.name = #"1";
MyAnnotationClass *overflowLotAnnotation=[[MyAnnotationClass alloc] initWithCoordinate:CLLocationCoordinate2DMake( 39.047958, -76.852520)];
overflowLotAnnotation.name = #"2";
//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
[mapView addAnnotations:_myAnnotations];
viewForAnnotation code :
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *parkingAnnotationIdentifier=#"ParkingAnnotationIdentifier";
if([annotation isKindOfClass:[MyAnnotationClass class]]){
//Try to get an unused annotation, similar to uitableviewcells
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:parkingAnnotationIdentifier];
//If one isn't available, create a new one
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:parkingAnnotationIdentifier];
if([((MyAnnotationClass *)annotation).name isEqualToString: #"1"]){
annotationView.image=[UIImage imageNamed:#"passenger.png"];
}
else if([((MyAnnotationClass *)annotation).name isEqualToString: #"2"]){
annotationView.image=[UIImage imageNamed:#"place.png"];
}
}
return annotationView;
}
return nil;
}
This is how you can add separate image for every point on MapKit.
you have to use the -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation; , a MKAnnotation delegate method
wich allow you to set a given annotation on the map.
This method is returned for every annotations, you just have to find the end and start annotations and set image to it
First, you have to implement the MKMapViewDelegate protocol and set the delegate class to your map.
In the MKMapView Delegate, declare the method:
- (MKAnnotationView *)mapView:(id)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if (annotation == [mapView userLocation]) // The user's blue point : no customisation.
return nil;
MKAnnotationView * annView = [mapView dequeueReusableAnnotationViewWithIdentifier:/* your specific identifier */];
if (annView == nil) {
annView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:/* your specific identifier */] autorelease];
}
annView.image = /* your image */;
return annView
}
But you have to detect if the annotation is the starting one or the ending one. You can set a specific title to easily retrieve it (like #"start") or subclass your MKAnnotations by adding a discriminating property.

How to show a call out for object that implements MkAnnotation protcol ?

I have an object that implements the MKAnnotation protocol:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface VoiceMemoryAnnotation : NSObject <MKAnnotation> {
NSString * blobkey;
}
#property (nonatomic, retain) NSString * blobkey;
-(id)initWithBlobkey:(NSString *) key andCoordinate:(CLLocationCoordinate2D) c;
#end
Adding this object a map works perfectly since I can see the red pins being dropped. However, the problem arises when I want to set this object to show a callout.
I cannot do annotation.showCallOut=YES because an "MkAnnotation" does not have this property, but a MkAnnotationView does. How do I get around this?
I tried to implement the map callback "viewForAnnotation" to check for "VoiceMemoryAnnotation" and I try to return a new "MkAnnotationView" and set it's callout = YES, but I start to get a segmentation fault when I do this.
Any ideas what I"m doing wrong?
First you need to create your annotation object (the one that implements the MKAnnotation protocol) and add it to your map using something like
VoiceMemoryAnnotation*VMA = [[VoiceMemoryAnnotation alloc] init];
VMA.title = #"Title String";
VMA.subtitle = #"Subtitle String";
[self.mapView addAnnotation:VMA];
That will automatically call the following method which you will need to implement:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView*singleAnnotationView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:nil];
singleAnnotationView.canShowCallout = YES;
return singleAnnotationView;
}
In this implementation MKAnnotationView won't work, it needs to be MKPinAnnotationView.
I'm not sure I completely understand your question, but I wonder, is MKMapViews's - (void)selectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated what you're looking for?

Loading data in Views depending on MapKit annotation callout click

I have a map with a disclosure button on the callout of it's annotations, which when clicked displays a detail view. Each point on the map needs to load up different data in the detail view - I dont want to build separate views for each annotation, for obvious reasons, but I am unsure of the best way to do this.
How do I flag which annotation has been clicked, so I can load the correct data through the detail's view controller?
You can implement the data loading function in your annotation class. To do that you will need to have a reference to that data in your annotation class.
Your annotation class can be something like
#interface MyAnnotation : NSObject<MKAnnotation> {
CLLocationCoordinate2D coordinate;
MyDataObject *mydataObject;
}
- (id) initWithCoordinate:(CLLocoationCoordinate2D)coord withMyData:(MyDataObject*)aDataObject;
- (void) loadDetailView; // this function will load the data in myDataObject to the DetailView
To get the callout touch, you can implement calloutAccessaryControlTapped function in the controller where you implement MKMapViewDelegate.
The function will be something like
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
MyAnnotation *myAnnotation = (MyAnnotation*)view.annotation;
[myAnnotation loadDetailView];
}
Edit
The implementation of initWithCoordinate will be something like:
#implementation MyAnnotation
....
- (id) initWithCoordinate:(CLLocoationCoordinate2D)coord withMyData:(MyDataObject*)aDataObject{
coordinate = coord; // cannot use "self.coordinate" here as CLLocationCoordinate2D is double instead of object (?)
self.title = <# some name #> // assign some string to the title property
self.mydataObject = aDataObject; // this is your data object
return self;
}
....

Mapkit with multi annotation (callout), mapping the next view

Wanted some help with a problem with mapkit I am facing. Should be a silly problem or I have missed out something while going through the mapkit framework.
Here is the senario.
I am placing multiple annotation on the map when the user performs some search like pizza.
Added button for the right annotation view, on click which opens a next detail view. The problem is how to send some information to the next view, for example I add index to annotations while creating them, now I want to access this information from annotation, and pass it to the next view via the selector set on the button.
I have checked all the mapkit delicate, but don't find a one where I can map this information with the next view and annotation.
Hope I have not confused you guys in my question. Please let me know I will reframe it.
Thaking in advance.
When you create the UIButton for the annotation, set the tag property (tag is an NSInteger property of UIView) to an id or array index that identifies the relevant object. You can then retrieve that tag value from the sender parameter to your selector.
Edit: here's some sample code.
You create your annotation view and associate the button in your delegate's -mapView:viewForAnnotation: method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// Boilerplate pin annotation code
MKPinAnnotationView *pin = (MKPinAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier: #"restMap"];
if (pin == nil) {
pin = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: #"restMap"] autorelease];
} else {
pin.annotation = annotation;
}
pin.pinColor = MKPinAnnotationColorRed
pin.canShowCallout = YES;
pin.animatesDrop = NO;
// now we'll add the right callout button
UIButton *detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
// customize this line to fit the structure of your code. basically
// you just need to find an integer value that matches your object in some way:
// its index in your array of MKAnnotation items, or an id of some sort, etc
//
// here I'll assume you have an annotation array that is a property of the current
// class and we just want to store the index of this annotation.
NSInteger annotationValue = [self.annotations indexOfObject:annotation];
// set the tag property of the button to the index
detailButton.tag = annotationValue;
// tell the button what to do when it gets touched
[detailButton addTarget:self action:#selector(showDetailView:) forControlEvents:UIControlEventTouchUpInside];
pin.rightCalloutAccessoryView = detailButton;
return pin;
}
Then in your action method, you'll unpack the value from tag and use it to display the right detail:
-(IBAction)showDetailView:(UIView*)sender {
// get the tag value from the sender
NSInteger selectedIndex = sender.tag;
MyAnnotationObject *selectedObject = [self.annotations objectAtIndex:selectedIndex];
// now you know which detail view you want to show; the code that follows
// depends on the structure of your app, but probably looks like:
MyDetailViewController *detailView = [[MyDetailViewController alloc] initWithNibName...];
detailView.detailObject = selectedObject;
[[self navigationController] pushViewController:detailView animated:YES];
[detailView release];
}
In the Annotation view, is it possible to grab,say, the Title or Subtitle or any other information you used while creating pins? What i am looking to do is have a certain image popup in the annotation based on one of those variables.
#import "MapPin.h"
#implementation MapPin
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
#synthesize indexnumber;
#synthesize imageFile;
-(id)initWithCoordinates:(CLLocationCoordinate2D)location
placeName: placeName
description:description
indexnum:indexnum
imageFileLoc:imageFileLoc{
self = [super init];
if (self != nil) {
imageFile=imageFileLoc;
[imageFile retain];
indexnumber=indexnum;
[indexnumber retain];
coordinate = location;
title = placeName;
[title retain];
subtitle = description;
[subtitle retain];
}
return self;
}
-(void)addAnnotations {
// Normally read the data for these from the file system or a Web service
CLLocationCoordinate2D coordinate = {35.9077803, -79.0454936};
MapPin *pin = [[MapPin alloc]initWithCoordinates:coordinate
placeName:#"Keenan Stadium"
description:#"Tar Heel Football"
indexnum:#"1"
imageFileLoc:#"owl.jpg"];
[self.map addAnnotation:pin];
Another option:
You can implement these methods:
- (void)mapView:(MKMapView *)mapView didSelectAnnotation:(MKAnnotationView *)view;
- (void)mapView:(MKMapView *)mapView didDeselectAnnotation:(MKAnnotationView *)view;