Reputation: 6969
In my app I have two address UITextfields to be filled up using address text. I want this behavior:
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?
Upvotes: 2
Views: 3833
Reputation: 438232
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.
Upvotes: 7