I am working with MKPinAnnotationView annotations pins over a MKMapView. Into the view that I am developing, there is a map centered on a pin. When I call the view the pin drops down and if I make a click over it, it shows the annotation information (canShowCallout = YES). How I can get this callout just when I open the view? Without making a click over the annotation pin.
Thanks for reading.
Edited:
I am using this code.
- (void)viewDidLoad {
[super viewDidLoad];
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:self.currentAnnotationCoordinate] autorelease];
[self.mapView addAnnotation:annotation];
[self zoomCoordinate:self.currentAnnotationCoordinate];
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
else { // Handles the other annotations.
// Try to dequeue an existing pin view first.
static NSString *AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView) {
// If an existing pin view was not available, creates one.
MKPinAnnotationView *customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
// Adds a detail disclosure button.
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
} else
pinView.annotation = annotation;
}
return nil;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)theMapView {
AddressAnnotation *annotation = [[[AddressAnnotation alloc] initWithCoordinate:self.currentAnnotationCoordinate] autorelease];
for (id<MKAnnotation> currentAnnotation in mapView.annotations) {
if ([currentAnnotation isEqual:annotation]) {
[mapView selectAnnotation:currentAnnotation animated:FALSE];
}
}
}
Edited:
Calling didAddAnnotationViews: instead of mapViewDidFinishLoadingMap: (as aBitObvious has commented), it works fine.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
id<MKAnnotation> myAnnotation = [self.mapView.annotations objectAtIndex:0];
[self.mapView selectAnnotation:myAnnotation animated:YES];
}
Possible duplicate: How to trigger MKAnnotationView's callout view without touching the pin?
You want to call [mapView selectAnnotation:].
Related
Hope someone can help, I'm trying to implement dropping one single Pin on a mapView. But I want the pin to be able to be dragged around and and dropped and for this annotation to be separate from the annotation for the user's location. Whilst the below code works, it creates duplicate pins for a user's touch and the pins can not be dragged around:
- (void)dropPinFromPress:(UIGestureRecognizer *)recognizer {
// Add Pin from User's Touch
if (recognizer.state != UIGestureRecognizerStateBegan) {
return;
}
// convert touched position to map coordinate
CGPoint userTouch = [recognizer locationInView:self.mapView];
CLLocationCoordinate2D mapPoint = [self.mapView convertPoint:userTouch toCoordinateFromView:self.mapView];
// Add Pin from user's touch
Annotation *pin = [[Annotation alloc]initWithLocation:mapPoint];
[self.mapView addAnnotation:pin];
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKAnnotationView *a = [ [ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier:#"currentloc"];
// a.title = #"test";
if ( a == nil )
a = [ [ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier: #"currentloc" ];
NSLog(#"%f",a.annotation.coordinate.latitude);
NSLog(#"%f",a.annotation.coordinate.longitude);
CLLocation* currentLocationMap = [[[CLLocation alloc] initWithLatitude:a.annotation.coordinate.latitude longitude:a.annotation.coordinate.longitude] autorelease];
[self coordinatesToDMS:currentLocationMap];
MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:a reuseIdentifier:#"currentloc"];
if(a.annotation.coordinate.longitude == mapView.userLocation.coordinate.longitude || a.annotation.coordinate.latitude == mapView.userLocation.coordinate.latitude )
{
if ([annotation isKindOfClass:MKUserLocation.class])
{
//user location view is being requested,
//return nil so it uses the default which is a blue dot...
return nil;
}
//a.image = [UIImage imageNamed:#"userlocation.png"];
//a.pinColor=[UIColor redColor];
}
else
{
// annView.image =[UIImage imageNamed:#"map-pin.png"];
//PinFirst=FALSE;
//annView.pinColor = [UIColor redColor];
// annView.annotation=annotation;
}
annView.animatesDrop = YES;
annView.draggable = YES;
annView.canShowCallout = YES;
return annView;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(#"map Drag");
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
fromOldState:(MKAnnotationViewDragState)oldState;
{
NSLog(#"pin Drag");
if (newState == MKAnnotationViewDragStateEnding)
{
CLLocationCoordinate2D droppedAt = view.annotation.coordinate;
NSLog(#"Pin dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
CLLocation* draglocation = [[[CLLocation alloc] initWithLatitude:droppedAt.latitude longitude:droppedAt.longitude] autorelease];
}
}
I have an MKMapView, that I drop a number of pins on from an array. Each map pin has an MKAnnotationView that links to a segue and another controller.
All of this is working perfectly now, but I can't see how to pass a variable through the MKAnnotationView to the segue.
I can work with either passing a string or an integer, as I could pass a username as a string, or pass the id of the array and use that in the second view controller after the segue.
My working code for looping through my array, dropping the pins, adding the annotations, and then calling the segue is as below.
This all works fine, populates the map, drops the bins, and the annotations work and link to the new segue. This is all perfect!
I just need to be able to pass a variable through from the map pin array to the second view controller segue.
- (void)loadMapPins {
for (int i=0; i<maparray.count; i++){
Location *item = _feedItems1[i];
CLLocationCoordinate2D myCoordinate = {[item.latitude doubleValue], [item.longitude doubleValue]};
MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
point.coordinate = myCoordinate;
point.title = item.firstname;
point.subtitle = [NSString stringWithFormat: #"%#", item.username];
[self.mapView addAnnotation:point];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation {
if (annotation == self.mapView.userLocation) return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* customPin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
customPin.pinColor = MKPinAnnotationColorRed;
customPin.animatesDrop = YES;
customPin.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPin.rightCalloutAccessoryView = rightButton;
return customPin;
}
- (IBAction)showDetails:(id)sender {
[self performSegueWithIdentifier:#"showProfileFromMap" sender:self];
}
You should use this MKMapViewDelegate method
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
CustomAnnotationClass *annotation = view.annotation;
selectedAnnotationVariable = annotation.yourProperty;
[self performSegueWithIdentifier:#"performSegue" sender:self];
}
HI I have requirement to Implement Next and Previous functionality in the MKMapAnnotationView as shown in the Image.I have got reference from Here for making custom annotation but how can i change the next or previous annotation by clicking Next and Previous button.Please provide some Hint or idea regarding this.I am stack at this point.
For that you can use the rightCalloutAccessoryView and leftCalloutAccessoryView.
Here an example how to use the rightCalloutAccessoryView.
-(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 setCanShowCallout:YES];
if([annotation isKindOfClass:[ASPinAnnotation class]])
{
[pinView setPinColor:MKPinAnnotationColorRed];
}
else if([annotation isKindOfClass:[ASAddAutomatPin class]])
{
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:[annotation title] forState:UIControlStateNormal];
[pinView setRightCalloutAccessoryView:rightButton];
[pinView setPinColor:MKPinAnnotationColorPurple];
}
And to get notified when a calloutAccessoryView is tapped you have to use this function in your delegate:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
if([(UIButton*)control buttonType] == UIButtonTypeDetailDisclosure)
{
ASAddViewController *addController = [[ASAddViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addController];
[addController setDelegate:self];
[self.controller presentViewController:navController animated:YES completion:nil];
}
}
It doesn't give me any errors or warnings as well. I don't know what other relevant info or details I can provide. Please tell me if it's not enough.
_mapView.delegate is set to self
Method in which the calloutAccessoryControl is set:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
NSLog(#"Enter viewForAnnotation delegate");
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MapViewAnnotation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
UIImageView *callOutButtonImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrow.png"]];
annotationView.rightCalloutAccessoryView = callOutButtonImage;
annotationView.image=[UIImage imageNamed:#"green-node.png"];
return annotationView;
}
return nil;
}
calloutAccessoryControlTabbed:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
NSLog(#"Control Tabbed!");
_scrollView.hidden = false;
}
The following is from the mapView:annotationView:calloutAccessoryControlTapped: discussion in the MKMapViewDelegate protocol reference document:
Accessory views contain custom content and are positioned on either side of the annotation title text. If a view you specify is a descendant of the UIControl class, the map view calls this method as a convenience whenever the user taps your view. You can use this method to respond to taps and perform any actions associated with that control. For example, if your control displayed additional information about the annotation, you could use this method to present a modal panel with that information.
I can see that you've added a UIImage to your annotation view's right callout accessory view. A UIImage object does not inherit from UIControl. A UIButton object would work.
I have some problems with adding annotations when the user touch the map.
I'm using UIGestureRecognizer to detect the user's touch.
When a long press is detected, I'm calling this function :
- (void)handleLongPressGesture:(UIGestureRecognizer*)gestureRecognizer{
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) return;
NSLog(#"long press");
CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate =
[mapView convertPoint:touchPoint toCoordinateFromView:mapView];
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
[rdvAnnotation initWithCoordinate:touchMapCoordinate];
[mapView removeAnnotations:mapView.annotations];
[mapView addAnnotation:rdvAnnotation];
[rdvAnnotation release]; }
I cans see the NSLog in the console and the rdvAnnotation is initialized with the good coordinate.
I don't understand why I can't see my annotation on the map.
Here's my - (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation method:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[RdvAnnotation class]])
{
static NSString* RdvAnnotationIdentifier = #"rdvAnnotationIdentifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)
[mapView dequeueReusableAnnotationViewWithIdentifier:RdvAnnotationIdentifier];
if (!pinView)
{
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:RdvAnnotationIdentifier] autorelease];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;}
My viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
mapView = [[MKMapView alloc] initWithFrame:self.view.frame];
[mapView setShowsUserLocation:TRUE];
[mapView setMapType:MKMapTypeStandard];
[mapView setDelegate:self];
CLLocationManager *locationManager=[[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager startUpdatingLocation];
self.navigationItem.title = #"Rendez-vous" ;
}
I just noticed something that seems weird :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
[rdvAnnotation initWithCoordinate:touchMapCoordinate];
You're calling init twice on the annotation object. You should just do it this way :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] initWithCoordinate:touchMapCoordinate]];
EDIT :
If you have code in your init method that you don't want to lose, keep the init and change the value of the coordinate property :
RdvAnnotation *rdvAnnotation = [[RdvAnnotation alloc] init];
rdvAnnotation.coordinate = touchMapCoordinate;
In viewDidLoad you are creating a new map view object.
First, this new map view object is not being added as a subview to self.view so it exists in memory but is invisible.
Second, you probably already have a map view object placed in the view in Interface Builder so you don't need to create a new one.
So what is probably happening is that when you add the annotation, it is being added to the map view object in memory but not the one that is visible (the one that was created in IB).
Instead of creating a new map view in viewDidLoad, connect the mapView IBOutlet to the map view in Interface Builder.