I add custom MKOverlayRenderer to MKMapView,Then I remove it with
removeOverlays() but overlay stays there for a while, mkmapview updates the drawing, most of the time i move mkmapview region somewhere then back. is there a method to set that will force mkmapview render immediately?
I ran into this same issue. I found online that
self.mapView.removeOverlays(self.mapView.overlays)
should remove them but it doesn't.
Turns out you have to create your MKPolylineRenderer or overlays as ivar.
var directionLineRenderer = MKPolylineRenderer()
func remove() {
if self.mapView.overlays.count != 0 {
self.mapView.remove(self.directionLineRenderer.overlay)
}
}
Related
I'm using Swift 3 and I want to create a moving marker in my map view, so that if the user touches the screen and moved the marker also moves with the page.
How can I fix this?
Use GMSMapViewDelegate method :
mapView:didChangeCameraPosition:
Set GMSMarker in this method at camera position.
This method call when camera position change in map.
func mapView(mapView: GMSMapView, didChangeCameraPosition position: GMSCameraPosition) {
// Apply set marker logic here
}
Is it possible to change a GMSPolygon .fillColor property from the didTapOverlay GMSMapViewDelegate delegation method? This is the delegation method:
func mapView(mapView: GMSMapView, didTapOverlay overlay: GMSOverlay)
my problem is that GMSPolygon inherits from GMSOverlay and the overlay doesn't have a fillColor property. The result I would like to achieve is to change the color of the polygon when the user taps it
Thanks
I met the same situation before (I used Objective-C for that time).
My solution was that generating unique IDs(random strings or number), then set them to the title property of each GMSPolygons.
The below code is written by Objective-C, but you might understand
- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay {
NSString *overlayClass = NSStringFromClass([overlay class]);
if ([overlayClass isEqualToString:#"GMSPolygon"] ||
[overlayClass isEqualToString:#"GMSPolyline"] ||
[overlayClass isEqualToString:#"GMSCircle"] ||
[overlayClass isEqualToString:#"GMSGroundOverlay"]) {
[self triggerOverlayEvent:#"overlay_click" id:overlay.title]; // <-- here
}
}
Of course, you need to manage all polygons (and others) with the generated IDs by yourself.
I have found a simple (single line) way to do that. Since GMSPolygon is a subclass of GMSOverlay we can cast him to be a GMSPolygon object, the delegate method will continue to work normally and it will treat it as a GMSPolygon object, changing it's .fillColor property.
Here's the code:
func mapView(mapView: GMSMapView, didTapOverlay overlay: GMSOverlay) {
/* Here we cast the GMSOverlay to be a GMSPolygon */
let overlay = overlay as! GMSPolygon
overlay.fillColor = UIColor.whiteColor()
/* Now the color of the polygon has changed on the map */
}
I working around with map app, I want to ask how to change the polyline color without remove and add it again, I found this topic https://stackoverflow.com/questions/24226290/mkpolylinerenderer-change-color-without-removing-overlay in stackoverflow but this is not involve with my question, I did not touch the line, so no need to do with -[MKMapViewDelegate mapView:didSelectAnnotationView:]
So is it possible to do that?
EDIT: What I want to do is change the polyline color smoothly (by shading a color - sound like an animation) If you have any idea on how to animate this polyline please also tell me too. Thanks
Complex animations or shading/gradients will probably require creating a custom overlay renderer class.
These other answers give ideas about how to draw gradient polylines and animations will most like require a custom overlay renderer as well:
how to customize MKPolyLineView to draw different style lines
Gradient Polyline with MapKit ios
Draw CAGradient within MKPolyLineView
Apple's Breadcrumb sample app also has an example of a custom renderer which you may find useful.
However, if you just want to update the line's color (say from blue to red), then you may be able to do that as follows:
Get a reference to the MKPolyline you want to change.
Get a reference to the MKPolylineRenderer for the polyline obtained in step 1. This can be done by calling the map view's rendererForOverlay: instance method (not the same as the mapView:rendererForOverlay: delegate method.
Update the renderer's strokeColor.
Call invalidatePath on the renderer.
Not sure what you want but you may be able to "animate" the color going from blue to red by changing the color and calling invalidatePath gradually in timed steps.
Another important thing is to make sure the rendererForOverlay delegate method also uses the line's "current" color in case the map view calls the delegate method after you've changed the renderer's strokeColor directly.
Otherwise, after panning or zooming the map, the polyline's color will change back to whatever's set in the delegate method.
You could keep the line's current color in a class-level variable and use that in both the delegate method and the place where you want to change the line's color.
An alternative to a class-level variable (and probably better) is to either use the MKPolyline's title property to hold its color or a custom polyline overlay class (not renderer) with a color property.
Example:
#property (nonatomic, strong) UIColor *lineColor;
//If you need to keep track of multiple overlays,
//try using a NSMutableDictionary where the keys are the
//overlay titles and the value is the UIColor.
-(void)methodWhereYouOriginallyCreateAndAddTheOverlay
{
self.lineColor = [UIColor blueColor]; //line starts as blue
MKPolyline *pl = [MKPolyline polylineWithCoordinates:coordinates count:count];
pl.title = #"test";
[mapView addOverlay:pl];
}
-(void)methodWhereYouWantToChangeLineColor
{
self.lineColor = theNewColor;
//Get reference to MKPolyline (example assumes you have ONE overlay)...
MKPolyline *pl = [mapView.overlays objectAtIndex:0];
//Get reference to polyline's renderer...
MKPolylineRenderer *pr = (MKPolylineRenderer *)[mapView rendererForOverlay:pl];
pr.strokeColor = self.lineColor;
[pr invalidatePath];
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineRenderer *pr = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
pr.strokeColor = self.lineColor;
pr.lineWidth = 5;
return pr;
}
return nil;
}
Yous hould look at MKOverlayPathRenderer method
- invalidatePath.
From the doc, it says:
Call this method when a change in the path information would require
you to recreate the overlay’s path. This method sets the path property
to nil and tells the overlay renderer to redisplay its contents.
So, at this moment, you should be able to change your drawing color.
I have an overlay on the map, and I would like to change its coordinates. To do this seamlessly I'm going to call the setNeedsDisplayInMapRect: method after the change has been made to the view.
I've tested this out by just changing the fillColor and it works fine:
overlayView.fillColor = [[UIColor greenColor] colorWithAlphaComponent:0.3];
[overlayView setNeedsDisplayInMapRect:mapView.visibleMapRect];
However I've seemingly hit a brick wall trying to also change the center coordinates of my overlay view (which is an MKCircleView with an MKCircle). There is a method in
MKAnnotation, which MKCircle conforms to, called setCoordinate: - which seems like what I need. Unfortunately though, the circle property in MKCircleView is readonly. Moreover the overlay property in MKOverlayView is also readonly.
Is there actually a way of changing the coordinates for an overlay, without resort to remove the overlay view and adding a new one (which would cause very noticeable flicker on the screen.) ?
same problem is occurred here , so i'm creating set of method and calling it according to requirement.
-(void)removeAllAnnotationFromMapView{
if ([[self.tmpMapView annotations] count]) {
[self.tmpMapView removeAnnotations:[self.tmpMapView annotations]];
}
}
-(void)removeAllOverlays{
if ([[self.tmpMapView overlays] count]) {
[self.tmpMapView removeOverlays:[self.tmpMapView overlays]];
}
}
-(void)removeOverlayWithTag:(int)tagValue{
for (MKOverlayView *oView in [self.tmpMapView overlays]) {
if (oView.tag == tagValue) {
[self.tmpMapView removeOverlay:oView];
}
}
}
I have a MKMapView with some custom annotations that don't look that great when the map is zoom far out.
Is it possible to only show/add them when the map is at a certain zoom level?
Using Marko's answer I came to this solution.
Everytime region changes, I change the ViewController's property isAtBigZoom.
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
isAtBigZoom = mapView.region.span.latitudeDelta < 0.01
}
Then at didSet of the property, I execute this code.
var isAtBigZoom = false {
didSet {
// this guard ensures, that the showing and hiding happens only once
guard oldValue != isAtBigZoom else {
return
}
// in my case I wanted to show/hide only a certain type of annotations
for case let annot as MapTextAnnotation in mapView.annotations {
mapView.viewForAnnotation(annot)?.alpha = isAtBigZoom ? 1 : 0
}
}
}
If you also want to start with the annotations hidden, just add the alpha changing code to viewForAnnotation method.
Works great and I haven't noticed big issues with performance. Though that may change with the increasing number of annotations...
You can get the map zoom level via
[map region];
property of the MKMapView. also you get the notifications for region changing events
by implementing the MKMapViewDelegate method and setting the delegate
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
here you can check what your current zoom level is. I don't recommend removing or adding all the annotations while zooming / panning since that could really effect the app performance. I haven't really tried setting alpha to 0.0 or hidden property on MKAnnotationView, but that could be your best bet.