Placing uipopovercontroller arrow at annotation point on mapkit
I'm trying to get a popover to appear at the mapset's annotation point, but can't find "rect" in the properties of the annotation view so that I can use the rect method to call the uipopovercontroller. If you have annotated on a set of maps, how do you find a suitable "frame"?
To give more information, here's my attempt: I've already used:
- (void)mapView:(MKMapView *)mapView2 annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
NSLog(@"annotationView...");
MyGizmoClass *myGizmoClass= [MyGizmoClass sharedManager];
int choice = 0;
for (NSMutableDictionary *locationDictionary in [myGizmoClass searchResultsForResortLocation])
{
if([view.annotation.title isEqualToString:[locationDictionary objectForKey:@"name"]])
{
DetailViewTableStyleController *controller = [[DetailViewTableStyleController alloc] initWithlocationData:[[myGizmoClass searchResultsForResortLocation] objectAtIndex:choice] nibName:@"DetailViewTableStyle" bundle:[NSBundle mainBundle]];
controller.categoryCode = [locationDictionary objectForKey:@"category_code"] ;
//create a popover controller
popoverControllerDetail = [[UIPopoverController alloc] initWithContentViewController:controller];
// set contentsize
[popoverControllerDetail setPopoverContentSize:CGSizeMake(320,480)];
//present the popover view non-modal
[popoverControllerDetail presentPopoverFromRect:view.rightCalloutAccessoryView.frame inView:mapView2 permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[controller release];
break;
}
choice = choice + 1;
}
}
And ... I get a popover at the top left at the edge of the map.
Can anyone tell me why? I am trying to get it to appear near the pin / annotationview pin.
a source to share
Okay,
Here's what I found as the only working point:
CGPoint annotationPoint = [mapView2 convertCoordinate:view.annotation.coordinate toPointToView:mapView2];
float boxDY=annotationPoint.y;
float boxDX=annotationPoint.x;
CGRect box = CGRectMake(boxDX,boxDY,5,5);
UILabel *displayLabel = [[UILabel alloc] initWithFrame:box];
[popoverControllerDetail presentPopoverFromRect:displayLabel.frame inView:mapView2 permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[displayLabel release];
The bad part about this is that I pretend to put it in the annotation field of view. I just get the annotation. Annotation coordinates (MKMapKit style coordinates) and convert coordinates to screen coordinates. Then I create a uilabel (to get the frame based construct on screen) positioned where the annotation will be viewed. Then I specify that the popovercontroller will appear at that point in the frame.
Here's the kicker. I am not adding uilabel to mapView2. I just release it as soon as the popovercontroller has drawn itself.
Hack but clean.
a source to share
The problem with the first example in this thread is the call to presentPopoverFromRect: inView: allowedArrowDirections: animated :. The inView parameter value is invalid. It should be view.rightCalloutAccessoryView.
That is, the coordinates of the rectangle are relative to the rightCalloutAccessoryView.
With this change, the behavior will be similar to that of a maps app, which appears to be correct.
a source to share
Didn't read all the answers ... but I had a similar problem. I wanted to show the popover box when I click the accessory button in the callout bubble. This is how I solved my problem.
I first focused the map on the annotation I chose and I think it's always a good idea in this case. Then I implement a fixed size popover and position it at the correct position (in my opinion).
Here is a portion of my code:
-(void)mapView:(MKMapView *)theMapView annotationView:(MKAnnotationView *)pin calloutAccessoryControlTapped:(UIControl *)control
{
UIViewController *detailController = [[detailedPinView alloc] initWithNibName:@"detailedPinView"
bundle:nil
annotationView:pin];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:detailController];
[aPopover setDelegate:self];
[aPopover setPopoverContentSize:CGSizeMake(320, 320) animated:YES];
[detailController setPopover:aPopover];
[detailController release];
[mapView deselectAnnotation:pin.annotation animated:YES];
self.popoverController = aPopover;
[mapView setCenterCoordinate:pin.annotation.coordinate animated:YES];
[self.popoverController presentPopoverFromRect:CGRectMake(382,498,0,0) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
else
{
[self presentModalViewController: detailController animated:YES];
}
[detailController release];
}
a source to share
The problem with presentPopoverFromRect: inView: allowedArrowDirections: animated is that if the size of the popover content is larger than the font size on the screen (because the annotation is covered by the edge of the screen, for example), the system will first (at least partially) ignore the rectangle and put the tip of the arrow is somewhere in the middle of the view. I solved it by doing this:
self.popover = [[UIPopoverController alloc] initWithContentViewController:placeDetailViewController];
[self.popover presentPopoverFromRect:CGRectMake(0, 0, 29, 31) inView:view.rightCalloutAccessoryView permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
The RightCalloutAccessoryView is usually a detail button that is 29x31 in size. So what I do is create a 29x31 rectangle that spans the entire accessory view. Then I present a popover from the accessory view. Increasing the value from 29-40 will position the popover arrow outside the callout bubble, but only if there is enough space on the screen to display the entire callout. If not, the arrow will be moved inside the bubble. To maintain a consistent interface, I left the width at 29.
a source to share