Anyone know if there's anyway to get a button onto an annotation?
I'd like the location to be selectable - so you can say.. select the location and get all the events at that location by clicking on the button.
is this possible?
w://
Here's the code I used for my annotation, it includes a button on the right side of the bubble. You can set an IBAction to push a new view onto the stack to display whatever you want
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinAnnotation == nil )
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinAnnotation.canShowCallout = YES;
//instatiate a detail-disclosure button and set it to appear on right side of annotation
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = infoButton;
}
return pinAnnotation;
}
I just helped someone else with this in objective c, but I'm sure the concept is the same with mono. You need to create a custom MKAnnotationView object and override the GetViewForAnnotation (viewForAnnotation in obj-c) method of your MKMapViewDelegate class... check out the other question.
When you create your custom MKAnnotationView object it is basically a UIView made for map annotations... you can just add your button and other info to the view and it will show up when the user hits the annotation.
Here some rough code for the delegate method:
public override MKAnnotationView GetViewForAnnotation(
MKMapView mapView,NSObject annotation) {
var annotationId = "location";
var annotationView = mapView.DequeueReusableAnnotation(annotationId);
if (annotationView == null) {
// create new annotation
annotationView = new CustomAnnotationView(annotation, annotationId);
}
else {
annotationView.annotation = annotation;
}
annotation.CanShowCallout = true;
// setup other info for view
// ..........
return annotationView;
}
}
Related
When clicking MKAnnotationViews on a map they are temporarily brought to the front. I don't want this behaviour has I have a lot of MKAnnotationViews that are just icons on the map that don't have any other function.
I've tried setting the MKAnnotationView's userInteractionEnabled to NO but it does not work. The MKAnnotationView still comes to the front when touched. This is confusing as MKAnnotationView is just a UIView so I can't work out why userInteractionEnabled is being ignored.
As mentioned in a previous answer (and the documentation), to disable touches on an annotation view, you can set its enabled property to NO.
Setting canShowCallout to NO is a potential alternative. However, that will not prevent the didSelectAnnotationView and didDeselectAnnotationView delegate methods from still getting called (even though the callout will not be displayed). That may be an issue depending on your situation.
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinView = nil;
//NSLog(#"my loc : %#",mapView.userLocation);
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"any";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
{
pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID] ;
}
//this property may help you
pinView.canShowCallout = NO;
}
SWIFT 4 example
We could reach our goal - Disable touches on MKAnnotationView with one really simple delegate method:
extension MyViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
for view in views {
view.isEnabled = false
}
}
}
If the value of this property is false, the annotation view ignores touch events and cannot be selected.
Combining with extension- and in summary, we get the elegant way of extending our ViewController with MKMapViewDelegate protocol conformance and unselectable MKAnnotationView!
Set MKPinAnnotationView *pinView or MKAnnotationView *annotationView property of user interaction to NO in the method where u have created them i.e
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
(id <MKAnnotation>)annotation{
static NSString *annotation = #"identifier";
MKAnnotationView * aView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( aView == nil )
{
aView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:annotation] ;
}
[aView setUserInteractionEnabled:NO];
}
I'm trying to make a custom annotation view able to respond to touches without success.
Thanks to this question I was able to made an annotation view close to what I want customize callout bubble for annotationview? also seen this How to capture touches and NOT dismiss the callout? but the problem is quite different
The first thing I've done so far is subclassing an MKAnnotationView and override the -setSelected:animated: method
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if(selected)
{
MyCallOut * callOut=[MyCallOut createMyCallOut];
callOut.tag=555;
[self.superview addSubview:callOut];
}
else
{
// [[self viewWithTag:555] removeFromSuperview];
//Remove my custom CallOut
}
}
The problem is that the map view is eating all the touches event, my custom callout has two buttons but no action is triggered pressing them.
In one of my experiment I've tried to add the callout view to the MKAnnotationView superview (the mapView) everything seems to be fine while I scroll, but If I zoom the callout moves around.
you have to add call out accessory view in map annotation
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *pinView = nil;
if(annotation != mapView.userLocation)
{
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorRed;
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return pinView;
}
else {
[mapView.userLocation setTitle:#"I am here"];
}
return pinView;
}
and for click event of your call out
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
}
Solved looking to this link Custom annotation and callouts, the other tricky part is implement a correct way to press button on the fake callout. I managed this part creating a boolean value that understands the number of annotation/parentAnnotation on screen and choose when one could disappear or not.Just need to make the CalloutAnnotation available to selection.
I have custom annotation pin at app:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
return [kml viewForAnnotation:annotation type:state];
}
where I return custom view and make setImage for annotationView of Placemark such as:
- (MKAnnotationView *)viewForAnnotation:(id <MKAnnotation>)point type:(int)state
{
// Find the KMLPlacemark object that owns this point and get
// the view from it.
for (KMLPlacemark *placemark in _placemarks) {
if ([placemark point] == point)
{
UIButton *disclosureButton = [UIButton buttonWithType: UIButtonTypeDetailDisclosure];
[[placemark annotationView] setCanShowCallout: YES];
[[placemark annotationView] setRightCalloutAccessoryView:disclosureButton];
if (state == 0)
{
[[placemark annotationView] setImage:[UIImage imageNamed:#"ic_pin_tour.png"]];
}
else
{
[[placemark annotationView] setImage:[UIImage imageNamed:#"ic_pin_point.png"]];
}
return [placemark annotationView];
}
}
return nil;
}
but if I long tap at my annotation pin it changes appearance to its default view (RedPin).
I cannot understand what method is called on long tap. I tried to play with UITapGestureRecognizer, but did not find out. If I just tap annotation pin all works fine and my custom annotation pin view doesn't disappear.
You can see what I mean in this screenshot:
So, why annotation pin appearance changes on long tap?
So, if you want to use a custom image for an annotation view, always use a generic MKAnnotationView instead of an MKPinAnnotationView.
I have MKPinAnnotationView at just one place, when I replace it with MKAnnotationView everything works properly now:
- (MKAnnotationView *)annotationView
{
if (!annotationView) {
id <MKAnnotation> annotation = [self point];
if (annotation) {
MKAnnotationView *pin =
[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
pin.canShowCallout = YES;
annotationView = pin;
}
}
return annotationView;
}
For some odd reason the detail button somehow stopped appearing:
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKPinAnnotationView *pinAnnotation = nil;
if(annotation != mapView.userLocation)
{
MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"sadasdasd"];
if ( pinAnnotation == nil ){
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"sadasdasd"] autorelease];
/* add detail button */
NSLog(#"Here");
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinAnnotation.rightCalloutAccessoryView = infoButton;
}
}
return pinAnnotation;
}
Here is output.
Thanks in advance.
First problem is that pinAnnotation is declared twice in that method.
Once in the first line and second in the if(annotation != mapView.userLocation)... block. Because of this, the return statement returns nil because the outer variable is never set (resulting in a default MKAnnotationView callout with no accessory).
Change the second declaration to just an assignment.
Next problem is that you need to set canShowCallout to YES because the default is NO for an MKPinAnnotationView. You can do this after setting the accessory view:
pinAnnotation.canShowCallout = YES;
The above should fix the accessory button not showing.
Unrelated, but you also need to set the view's annotation property when it is being re-used (in the case when it is not nil after the dequeue). So add an else block to the if (pinAnnotation == nil):
else {
//annotation view being re-used, set annotation to current...
pinAnnotation.annotation = annotation;
}
I would change the color from red to green of an annotation when the user pin tapped addition to changing its title and subtitle.
I am truly lost. I searched how to make a custom annotation pin, ok. I found the implementation of the method when the user touches the pin didSelectAnnotationView and it works when I tap the annotation NSLog(#"Tap") ; , but now I can not change the pin that was touched.
Thank you very much everyone for your contributions.
Ciao
To set the pin color, make use of MKPinAnnotationView pinColor property.
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc] init]
pin.pinColor = MKPinAnnotationColorGreen;
For custom annotation image, set the image property, as such.
UIImage *annImage = [UIImage imageNamed:#"AnnotationIcon.png"];
annView.image = annImage;
Do note that the MKPinAnnotationView animateDrop property will not work on custom images. There's a way to duplicate that animation though. See How do I animate MKAnnotationView drop?
Update
So bascially, you do this if you wanna change from red to green upon being selected.
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorGreen;
}
- (MKAnnotationView *)mapView:(MKMapView *)aMapView
viewForAnnotation:(id)ann {
NSString *identifier = #"myPin";
MKPinAnnotationView *annView = (MKPinAnnotationView *)
[aMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annView == nil) {
annView= [[[MKPinAnnotationView alloc] initWithAnnotation:ann
reuseIdentifier:identifier]
autorelease];
} else {
annView.annotation = ann;
}
// you can define the properties here.
return annView;
}
In your method set the pinColor property of your MKAnnotationView as follows:
annotationView.pinColor = MKPinAnnotationColorRed; // Green or Purple
(re) look this :
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKPinAnnotationView *)view {
view.pinColor = MKPinAnnotationColorGreen;
}
this is a MKPinAnnotationView (and not MKAnnotationView) in param