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;
}
Related
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 want to display a 2 line label in the callout for current location.
MKUserLocation and not MKAnnotation
Can anybody help with how is it possible?
Am sure It would be possible with custom Callout.. But not sure how to create it for MKUserLocation.
In the viewForAnnotation method you could try this:
- (MKAnnotationView *)map:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>) annotation{
if(self._mapView.userLocation==annotation){
self._mapView.userLocation.title=#"some text";
self._mapView.userLocation.subtitle=#"some text";
return nil;
}
}
Hope this helps.
I assume you can create custom annotation callout and want to use instead of default callout for userlocation. To get this done one need to get reference of current location MKAnnotationView. One can get this reference anywhere but it is better to get it as soon as user location is determined.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKAnnotationView* annotationView = [mapView viewForAnnotation:userLocation];
annotationView.canShowCallout = NO;
//your customization here
}
Or use following method
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKAnnotationView *aV;
for (aV in views) {
if ([aV.annotation isKindOfClass:[MKUserLocation class]]) {
MKAnnotationView* annotationView = aV;
annotationView.canShowCallout = NO;
//your customization here
}
}
}
and if want to change in canShowCallout property in runtime then one can use following
for (AnnotationClass* annotation in mapView.annotations)
{
if([annotation isKindOfClass:[MKUserLocation class]] )
{
MKAnnotationView* annotationView = [mapView viewForAnnotation:annotation];
annotationView.canShowCallout = NO;
//your customization here
}
}
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
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;
}
}