I have a detailDisclousure button on the callout of a MKAnnotation. When this button is pressed I need to call a method passing a parameter that identifies the annotation that called it. How could it be done?
this is my viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[Annotation class]])
{
static NSString* identifier = #"identifier";
MKPinAnnotationView* pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (pinView == nil)
{
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]autorelease];
}
Annotation *antt = annotation;
pinView.canShowCallout = YES;
pinView.draggable = YES;
UIButton* detailButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[detailButton performSelector:#selector(goToViewWithAnnotation:) withObject:antt];
pinView.rightCalloutAccessoryView = detailButton;
return pinView;
}
else
{
return nil;
}
}
And this is the method that should be called with the parameter:
-(void)goToViewWithAnnotation:(Annotation *)annotation
{
NextViewController *nextView = [[NextViewController alloc]initWithNibName:#"NextViewController" bundle:nil];
nextView.id = annotation.id;
[self.navigationController nextView animated:YES];
}
you can pass any NSInteger via the tag property of the UIButton only.
It's not possible to send data with the -addTarget:action:forControlEvent: for UIButton:
[detailButton addTarget:self action:#selector(goToViewWithAnnotation:) forControlEvents:UIControlEventTouchUpInside];
Try to handle the data with some other way, when you trigger the selector. Like saving a pointer or var as you like.
UIButton have these callers as you can see:
- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event
I think you can add a property(which is (Annotation *)annotation) in .h file. Then you can use annotation in the "-(void)goToViewWithAnnotation" method. Or you can customized a new button which inherits UIControl
Related
I have a code for creating annotation view :
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id<MKAnnotation>)myannotation{
MKAnnotationView *view = nil;
view = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"identifier"];
if([myannotation isKindOfClass:[myAnnotation class]]){
if(nil == view) {
view = [[MKPinAnnotationView alloc] initWithAnnotation:myannotation
reuseIdentifier:#"identifier"];
view.canShowCallout = YES;
}
myAnnotation *anns= (myAnnotation*)myannotation;
_annimge=anns.Img;
UIButton *btnViewVenue = [UIButton buttonWithType:UIButtonTypeContactAdd];
[btnViewVenue addTarget:self action:#selector(ButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
btnViewVenue.titleLabel.text=#"GĂ“WNOKURWA";
view.rightCalloutAccessoryView=btnViewVenue;
}
return view;
}
I would like to show image on button press, thats why I signing image property of annotation to _annimge, but it only shows the last image added, no matter which annotation is active, same thing was happening with ID property which I added, it only returned the highest ID (last added).I am new at iOS and trying to fix this issue for way too long. Thanks for help.
I have simple app with Map and pins attached to it. After clicking on pin on map, pinView is created, on wchich I have button with action called let's say ButtonPressed.
I want to know from which pin it was pressed. I tried something like :
(IBAction)ButtonPressed:(id)sender
{
UIButton *but = (UIButton*) sender;
NSLog(#"SEG PLZ SEG CMON %tu",but.superview.tag);
[self performSegueWithIdentifier:#"segu" sender:sender];
}
But it always returns 0, no matter that I set tag for 5.
Okay I post code for adding buttons as you wanted :
- (MKPinAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)myannotation{
MKPinAnnotationView *view = nil;
//MKPinAnnotationView *view=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"HotSpotsLoc"];
if(myannotation !=mapView.userLocation){
view = (MKPinAnnotationView *)
[mapView dequeueReusableAnnotationViewWithIdentifier:#"identifier"];
if(nil == view) {
view = [[MKPinAnnotationView alloc]
initWithAnnotation:myannotation reuseIdentifier:#"identifier"];
}
UIButton *btnViewVenue = [UIButton buttonWithType:UIButtonTypeContactAdd];
[view.rightCalloutAccessoryView setTag:50];
[btnViewVenue addTarget:self action:#selector(ButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
view.rightCalloutAccessoryView=btnViewVenue;
view.enabled = YES;
view.pinColor = MKPinAnnotationColorPurple;
view.canShowCallout = YES;
view.multipleTouchEnabled = NO;
//view.animatesDrop = YES;
UIButton *btnViewwVenue = [UIButton buttonWithType:UIButtonTypeContactAdd ] ;
[btnViewwVenue addTarget:self action:#selector(addImage:) forControlEvents:UIControlEventTouchUpInside];
[view setTag:50];
view.leftCalloutAccessoryView=btnViewwVenue;
view.enabled = YES;
view.pinColor = MKPinAnnotationColorPurple;
view.canShowCallout = YES;
view.multipleTouchEnabled = NO;
}
return view;
}
Setting leftCalloutAccessoryView and rightCalloutAccessoryView does not necessarily add the views as subviews of view. If you need this relationship to be explicit, consider subclassing UIButton.
#interface MyButton : UIButton
#property (weak) MKPinAnnotationView *annotation;
#end
#implementation MyButton
#end
// Then...
(IBAction)ButtonPressed:(id)sender
{
MyButton *but = (MyButton*) sender;
NSLog(#"SEG PLZ SEG CMON %tu",but.annotation.tag);
[self performSegueWithIdentifier:#"segu" sender:sender];
}
I have two info buttons showing up within my callout view for some reason. I have 3 different pin colors that are pulling information from 3 different sources. I need each button for each pin color to push to a separate view controller based on that annotation class. i have the following code so far for my 3 different pin colors:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[annotation class]]) {
MKPinAnnotationView *view = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (view == nil) {
view = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation
reuseIdentifier:identifier];
} else {
view.annotation = annotation;
}
if([[(Annotation*)annotation phoneNumber] isEqualToString:#"0"]){
view.enabled = YES;
view.canShowCallout = YES;
view.pinColor = MKPinAnnotationColorPurple;
// Create a UIButton object to add on the
self.leftBtn = [UIButton buttonWithType:UIButtonTypeInfoDark];
[self.leftBtn setTitle:annotation.title forState:UIControlStateNormal];
[view setLeftCalloutAccessoryView:self.leftBtn];
}else{
view.enabled = YES;
view.canShowCallout = YES;
// Create a UIButton object to add on the
self.rightBtn = [UIButton buttonWithType:UIButtonTypeInfoDark];
[self.rightBtn setTitle:annotation.title forState:UIControlStateNormal];
[view setRightCalloutAccessoryView:self.rightBtn];
}
if ([[(Annotation*)annotation phoneNumber] isEqualToString:#"1"]){
view.enabled = YES;
view.canShowCallout = YES;
view.pinColor = MKPinAnnotationColorGreen;
// Create a UIButton object to add on the
self.leftBtn = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[self.leftBtn setTitle:annotation.title forState:UIControlStateNormal];
[view setLeftCalloutAccessoryView:self.leftBtn];
}
return view;
}
return nil;
}
And for my accessory tapped method I have the following:
- (void)mapView:(MKMapView *)map annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{
if(view.leftCalloutAccessoryView){
UserAnnotation *annotate = view.annotation;
BuydealsViewController *dealsView=[[BuydealsViewController alloc]initWithNibName:#"DealDetailsViewViewController" bundle:[NSBundle mainBundle]];
dealsView.urlString = annotate.url;
[self.navigationController pushViewController:dealsView animated:YES];
}
if(view.rightCalloutAccessoryView){
MapDealViewController *mapDeals = [[MapDealViewController alloc] init];
Annotation *annView = view.annotation;
mapDeals.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
mapDeals.phoneNumber = annView.phoneNumber;
mapDeals.address = annView.subtitle;
mapDeals.title = annView.title;
mapDeals.description = annView.description;
mapDeals.value = annView.value1;
mapDeals.discountPercent = annView.discountPercent;
mapDeals.price = annView.price;
mapDeals.header = annView.header;
mapDeals.imageUrl = annView.imageUrl;
mapDeals.url = annView.url;
mapDeals.dealy = annView.dealy;
self.navigationController.navigationBarHidden = NO;
[self.navigationController pushViewController:mapDeals animated:YES];
}
}
Is there any way to make them both right buttons but click to separate views?
First, this may not be causing any issues currently, but it's important to point out.
This line in viewForAnnotation:
if ([annotation isKindOfClass:[annotation class]])
looks wrong because of course annotation will be the same kind of class as itself.
This will always return YES.
You probably meant to write Annotation class with an uppercase A which is the class name (annotation with a lowercase a refers to the current annotation instance parameter):
if ([annotation isKindOfClass:[Annotation class]])
Regarding "I have two info buttons showing up within my callout view for some reason.":
Look at this simplified version of the current logic in viewForAnnotation:
if (phoneNumber is "0")
{
...
[view setLeftCalloutAccessoryView:self.leftBtn];
}
else
{
....
[view setRightCalloutAccessoryView:self.rightBtn];
}
if (phoneNumber is "1")
{
....
[view setLeftCalloutAccessoryView:self.leftBtn];
}
Notice that if phoneNumber is "1":
The view's rightCalloutAccessoryView is set in the else since "1" is not "0",
And the view's leftCalloutAccessoryView is set in the second if (since it is "1").
The logic for setting the accessory views needs to be adjusted according to what you want.
Note that you should explicitly set the view's leftCalloutAccessoryView or rightCalloutAccessoryView to nil when a given annotation should not have that accessory (and when other annotations might). This is because if an annotation view is re-used, its accessory views may already be set based on the annotation it was previously used for. So you might do something like this:
if (phoneNumber is "0")
{
...
view.leftCalloutAccessoryView = nil;
view.rightCalloutAccessoryView = [UIButton buttonWithType...];
}
else if (phoneNumber is "1")
{
...
view.leftCalloutAccessoryView = [UIButton buttonWithType...];
view.rightCalloutAccessoryView = nil;
}
else
{
//some default, unexpected case handling...
...
view.leftCalloutAccessoryView = nil;
view.rightCalloutAccessoryView = nil;
}
Also, there's no need to have leftBtn and rightBtn as properties and may cause confusion or other issues. Just declare them as local variables.
Regarding "Is there any way to make them both right buttons but click to separate views?":
Yes. You already have code in viewForAnnotation that does this:
You can check the annotation object's class (but do it correctly using the class name and not the instance variable).
You can cast annotation to your custom class and check custom property values (like phoneNumber).
I can't seem to be able to add a disclosure button to my map annotations.
I implemented the MKMapViewDelegate to my view controller as well. What am I missing?
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *mapPin = nil;
if(annotation != map.userLocation)
{
static NSString *defaultPinID = #"defaultPin";
mapPin = (MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (mapPin == nil )
mapPin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
mapPin.canShowCallout = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mapPin.rightCalloutAccessoryView = infoButton;
}
return mapPin;
}
That code should work but check the following:
Is the map view's delegate property set? Declaring that the view controller implements the MKMapViewDelegate protocol does not actually tell the map view which object is implementing the delegate methods. In code, do map.delegate = self; or in IB connect the delegate outlet to File's Owner.
Is the annotation's title property set to non-blank? If the title is blank, no callout will show.
Also, unrelated but, when the dequeue returns an annotation view, you should update its annotation property to the current annotation (it might have been used for another annotation previously). Additionally, unless you're using ARC, you should also autorelease the view.
- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *mapPin = nil;
if(annotation != map.userLocation)
{
static NSString *defaultPinID = #"defaultPin";
mapPin = (MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (mapPin == nil )
{
mapPin = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:defaultPinID] autorelease];
mapPin.canShowCallout = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
mapPin.rightCalloutAccessoryView = infoButton;
}
else
mapPin.annotation = annotation;
}
return mapPin;
}
I have a map view with pins annotations into it. I need to pass to the detail view the coordinates of a pin when the user press the disclosure button of the pin information. How can I get the coordinates of the pin when I am into the showDetails method? I am using the next code.
- (void)showDetails:(id)sender {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil ];
// HERE I NEED TO PASS THE COORDINATES OF THE PIN TO THE DETAILVIEWCONTROLLER.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
- (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;
}
Thanks for reading.
I cannot give you a working code solution right now since i don't have my mac here. But I can tell you about a possible approach.
Create a method in DetailViewController that populates its attributes, so you can call it from showDetails, before you push it. So the sequence of events would be like this.
Click on disclosure button -> showDetails called -> DetailViewController created and populated -> push DetailViewController
Hope this helped you
You can your UIButton button custom like this :
#interface CustomButton : UIButton {
CLLocationCoordinate2D pinCoordinate;
}
Now in your viewForAnnotation :
// Adds a detail disclosure button.
CustomButton *rightButton = [CustomButton buttonWithType:UIButtonTypeDetailDisclosure];
rightButton.pinCoordinate = annotation.coordinate
[rightButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
And finally to get the coordinate in the showDetails method :
CLLocationCoordinate2D currentCoord = ((CustomButton*)sender).pinCoordinate;