I have an annotation pin that I use to display the current search location which can be dragged. That annotation pin is dragging and then that pin is showing user drop the pin.How to do like this.
To make an annotation draggable, set the annotation view's draggable property to YES.
This is normally done in the viewForAnnotation delegate method.
For example:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *reuseId = #"pin";
MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (pav == nil)
{
pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
pav.draggable = YES;
pav.canShowCallout = YES;
}
else
{
pav.annotation = annotation;
}
return pav;
}
If you need to handle when the user stops dragging and drops the annotation,
see: how to manage drag and drop for MKAnnotationView on IOS?
how to manage drag and drop for MKAnnotationView on IOS?
In addition, your annotation object (the one that implements MKAnnotation) should have a settable coordinate property. You are using the MKPointAnnotation class which does implement setCoordinate so that part's already taken care of.
iOS 11.x Swift 4.0 answer, based on Ashish Thummar solution.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pav: MKPinAnnotationView? = self.mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pav == nil {
pav = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pav?.isDraggable = true
pav?.canShowCallout = true
} else {
pav?.annotation = annotation
}
return pav
}
Related
I want to show a UIView just above the pin location and if the user moves around the map the UIView should remain above the pin location. I dont want to use the callout bubble. Is there any other way?
in iOS 9 we have a new property named detailCalloutAccessoryView
You can create a view and set as
annotationView.detailCalloutAccessoryView = tempView
Please check the link to get more details
MapKit iOS 9 detailCalloutAccessoryView usage
Try using this code:
func mapView(_ mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView {
if (annotation is MKUserLocation) {
return nil
}
else if (annotation is YourAnnotationClassHere) {
let identifier = "MyCustomAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView {
annotationView.annotation = annotation
}
else {
annotationView = MKAnnotationView(annotation, reuseIdentifier: identifier)
}
annotationView.canShowCallout = false
// set to YES if using customized rendition of standard callout; set to NO if creating your own callout from scratch
annotationView.image = UIImage(named: "your-image-here.png")!
return annotationView
}
return nil
}
That's mainly what you need for that to work. This is a swift version of this answer right here: How to create Custom MKAnnotationView and custom annotation title and subtitle
Hope it helped!!!
I am trying to customize the annotations on the map, and instead of pins I want the annotations to look like the current location indicator. How would I do this? Any advice would be great!
In general you can use custom annotation object which extends MKPointAnnotation. But if you just need to change pin image you can avoid subclassing and just implement this method
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "MyPin"
if annotation.isKindOfClass(MKUserLocation) {
return nil
}
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if let annotationView = annotationView {
annotationView.annotation = annotation
} else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView.image = UIImage(named: "myPinImage")
}
return annotationView
}
So it's enough for you to find correct image and replace pins with it.
But if you want to follow possible changes of default currentLocation image you can reuse default view
let annotationView = mapView.viewForAnnotation(mapView.userLocation());
I'm trying to drop some pins that represent bus stops with an image, when I ad the image it changes the placement of the pin. When I do not set an image the pin is dropped in the correct place.
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is StopAnnotation {
let identifier = "stopAnnotation"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
pinView!.canShowCallout = true
pinView.image = UIImage(named: "stopIcon")
}
return pinView
}
return nil
}
Examples
The image I am trying to use:
Can anyone tell me why this is doing this? I am using the exact same image in my Obj-C version of this app and everything is working fine.
The code is creating an MKPinAnnotationView with a custom image.
The MKPinAnnotationView class should only be used to display the default pin images.
To show a custom image, it's better to use a plain MKAnnotationView.
Because the code is using an MKPinAnnotationView, the image is automatically getting an offset applied to it (the centerOffset property).
This built-in offset works for the default pin images but not for your custom image.
Rather than trying to override this default behavior, use a plain MKAnnotationView instead:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is StopAnnotation {
let identifier = "stopAnnotation"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if pinView == nil {
//println("Pinview was nil")
//Create a plain MKAnnotationView if using a custom image...
pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
pinView!.canShowCallout = true
pinView.image = UIImage(named: "stopIcon")
}
else {
//Unrelated to the image problem but...
//Update the annotation reference if re-using a view...
pinView.annotation = annotation
}
return pinView
}
return nil
}
How to show the user location icon(blue dot) on the top of the map view pin image.
Now the user location icon is hidden by the pin image.(below the pin image).
How to do this task ?(check screenshot)
Is it possible to show the user location icon on the top of the image ?
Thank you.
You can fetch the annotation for the userLocation and bring his view to front.
MKAnnotationView *annotationView = [self.mapView viewForAnnotation:self.mapView.userLocation];
[annotationView.superView bringSubviewToFront:annotationView];
This is probably happening because you are overriding the userLocation's annotation view.
On the Map View delegate method - mapView:viewForAnnotation:, you can do this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
<YourAnnotationViewClass> *annotationView = nil;
if (annotation != [mapView userLocation]) {
// Add custom annotation view
}
return annotationView;
}
In the case where annotation == [mapView userLocation], if you return nil, the default annotation (the blue circle, in this case) will be used.
public func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation is MKUserLocation) {
return nil
}
var annotationView: MKAnnotationView?
// personalize annotationView
return annotationView
}
Right now I am populating a map view with annotations, and also displaying the user's current location. With the viewForAnnotation method, it overrides all annotations with the default red pin, but I want to return the views for the other annotations, but keep the user location the default blue beacon. Is there a way to do this simply or do I have to create a new annotation view and return the right one depending on the annotation?
Right now I have something like:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation.coordinate == locationManager.location.coordinate) {
return nil;
}else {
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"Beacon"];
// Button
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
button.frame = CGRectMake(0, 0, 23, 23);
annotationView.rightCalloutAccessoryView = button;
annotationView.canShowCallout = YES;
return annotationView;
}
}
But I can't equate the two because I can't get the coordinate property out of the annotation argument.
Anybody know any solutions to this?
Check out the documentation here:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapViewDelegate_Protocol/MKMapViewDelegate/MKMapViewDelegate.html
As it states:
If the object in the annotation parameter is an instance of the
MKUserLocation class, you can provide a custom view to denote the
user’s location. To display the user’s location using the default
system view, return nil.
You can check for it like so:
if([annotation isKindOfClass: [MKUserLocation class]]) {
return nil;
}
Swift:
guard annotation as? MKUserLocation == nil else { return nil }
Swift 5.0
Put a check at the top of the function to ignore the userLocation:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard annotation as? MKUserLocation != mapView.userLocation else { return }