I have a MKMapView with some pins on it. I connect the pins with a MKPolyline view. But the MKPolyline is only shown when I move the map (when the MapView is updated?). I want to see the MKPolyline from the beginning on.
Please inspect the following code:
-(void)plotSnapPosition {
for (id<MKAnnotation> annotation in myMapView.annotations) {
[myMapView removeAnnotation:annotation];
}
for (id<MKOverlay> overlay in myMapView.overlays) {
[myMapView removeOverlay:overlay];
}
NSArray *snaps = self.entry.snapsArray;
CLLocationCoordinate2D *locations = malloc(sizeof(CLLocationCoordinate2D) * snaps.count);
NSInteger counter = 0;
for (Snap *snap in snaps) {
locations[counter] = [snap coordinates];
CLLocationCoordinate2D c = [snap coordinates];
CAHAnnotation *annotation = [[CAHAnnotation alloc] initWithDate:snap.timeAsString coordinate:c counter:counter];
[myMapView addAnnotation:annotation];
counter++;
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:locations count:snaps.count];
MKPolylineView *routeLineView = [[MKPolylineView alloc] initWithPolyline:polyline];
routeLineView.fillColor = [UIColor redColor];
routeLineView.strokeColor = [UIColor redColor];
routeLineView.lineWidth = 5;
[myMapView setVisibleMapRect:polyline.boundingMapRect];
[self.myMapView addOverlay:polyline];
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineView *routeLineView = [[MKPolylineView alloc] initWithPolyline:overlay];
routeLineView.fillColor = [UIColor blueColor];
routeLineView.strokeColor = [UIColor blueColor];
routeLineView.lineWidth = 3;
return routeLineView;
}
return nil;
}
For testing issues I have set the color of the MKPolyline in the method -(void)plotSnapPosition to red. In the delegate I set it to blue. Only the blue one is shown, after moving the map around.
can someone help me out of this? I think it is only a small mistake. Thank you.
here are the screenshots:
the two pins
after moving the map:
the path after moving the map
Make sure you set the mapView's delegate before adding the overlay. So, in your case
mapView.delegate = self;
[self plotSnapPosition];
Have you tried adding a [overlayView setNeedsDisplay] call when you finish drawing?
Related
I suppose that it's going to be a silly thing but I don't know how to solve it.
First I have to say that my trouble it is because that work sometimes.
I have a main controller which some categories, then touching buttons you can open other view controllers, in this view controllers there are a custom view which contains an mkmapview with annotations.
My problem is that in some categories it deploy the annotations and in the other ones it doesn't.
When it doesn't you can check that the annotations are inside of the MKMapView but it didn't call mapView:ViewForAnnotation until you interact with the map another time.
I will show some code:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect mapFrame = CGRectMake(0, 0, frame.size.width, frame.size.height);
mapViewDefault = [[MKMapView alloc] initWithFrame:mapFrame];
mapViewDefault.delegate = self;
NSLog(#"Eres delegado!");
CLLocationCoordinate2D initialLocationCoordinate = [DataManager dataManager].centerCoordinate;
[mapViewDefault setCenterCoordinate:initialLocationCoordinate];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(initialLocationCoordinate, 3000, 3000);
[mapViewDefault setRegion:viewRegion];
[mapViewDefault setUserInteractionEnabled:NO];
[mapViewDefault setScrollEnabled:NO];
[mapViewDefault setZoomEnabled:NO];
if(TAPIsiOS7()){
[mapViewDefault setRotateEnabled:NO];
}
[self addSubview:mapViewDefault];
}
return self;
}
- (void)addListOfPointsWithNumber:(NSArray*)arrayPoints {
NSLog(#"Añadimos anotación al array anotaciones");
[mapViewDefault removeAnnotations:mapViewDefault.annotations];
for (Place *place in arrayPoints) {
if(![place.coordinate isEqualToString:#"0 0"]){
Annotation *annotation = [[Annotation alloc] init];
annotation.coordinate = place.lCoordinate;
annotation.number = place.number;
annotation.place = place;
[mapViewDefault addAnnotation:annotation];
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if([annotation isKindOfClass:[Annotation class]]){
NSLog(#"Añadimos anotación al mapa");
Annotation *annotationMap = (Annotation *)annotation;
NSString *identifier = #"Pin";
UIImage *pinImage = [UIImage imageNamed:#"Pin.png"];
MKAnnotationView *pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.frame = CGRectMake(0, 0, pinImage.size.width, pinImage.size.height);
if (annotationMap.number>0) {
pinImage = [self imageWithView:pinImage andNumber:annotationMap.number];
}
pinView.image = pinImage;
pinView.annotation = annotationMap;
return pinView;
}
}
And 3 images:
I'm pretty sure that this code works great (because I can see that in other categories) and it has to be something with execution times.
If somebody has an idea about what is happening it should be nice.
Thank you all!
You should also be returning something in all cases in your mapView:viewForAnnotation:, whereas you are currently only returning for certain types of annotations. At least return nil and see if that helps -- maybe the warning on this method is preventing some sort of runtime use (though that's a bit of a stretch).
I am drawing a bunch of MKPolygons in my MKMapView. Some of them lay on top of each other. How can I bring a selected polygon to the top/front?
I tried bringSubviewToFront: on a MKPolygonView I create from the polygon layer:
MKPolygonView *view = (MKPolygonView *)[self.mapView viewForOverlay:polygon];
view.strokeColor = [UIColor orangeColor];
[self.mapView bringSubviewToFront:view];
SOLUTION:
I removed
MKPolygonView *view = (MKPolygonView *)[self.mapView viewForOverlay:polygon];
view.strokeColor = [UIColor orangeColor];
[self.mapView bringSubviewToFront:view];
and replaced it with what Craig suggested:
[self.mapView insertOverlay:polygon atIndex:self.mapView.overlays.count];
which then calls the MKMapKit delegate mapView:viewForOverlay: and then I handle the color change there:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolygon class]] && !((MKPolygon *)overlay).isSelected) {
MKPolygonView* aView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
aView.strokeColor = [UIColor yellowColor];
aView.lineWidth = 3;
return aView;
}
else if ([overlay isKindOfClass:[MKPolygon class]] && ((MKPolygon *)overlay).isSelected) {
MKPolygonView* aView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
aView.strokeColor = [UIColor orangeColor];
aView.lineWidth = 3;
return aView;
}
}
When you add an overlay to a mapView you can choose where to place it in the list of overlays. Since an overlay can only be in the list once you can move it just by inserting again at the desired location. Since you want it at the top, this should work:
[mapView insertOverlay:overlay atIndex:[mapView.overlays count]];
You should not be calling viewForOverlay. Leave that to iOS. If you need to colour the overlay do it within viewForOverlay because iOS can and will call that when ever it wants and if you return a non-coloured overlay that's what it will draw.
I have a mapView with 2 circles. When I try to customize the large one the small one seems to follow the large one. For example if I customize the fill color for the large one the smaller one gets the same color. How do I make the smaller one a different color? Note: I use reusable identifiers. Thank you.. this is my working code but when i try to edit my smaller circle, the one with radius 100 it doesn't. note: this is my WORKING code as anything else i tried it failed.
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
static NSString *CircleOverlayIdentifier = #"Circle";
_mapView.delegate = self;
if ([overlay isKindOfClass:[CircleOverlay class]]) {
CircleOverlay *circleOverlay = (CircleOverlay *)overlay;
MKCircleView *annotationView =
(MKCircleView *)[mapView dequeueReusableAnnotationViewWithIdentifier:CircleOverlayIdentifier];
if (!annotationView) {
MKCircle *circle = [MKCircle
circleWithCenterCoordinate:circleOverlay.coordinate
radius:circleOverlay.radius];
annotationView = [[MKCircleView alloc] initWithCircle:circle];
//this one
}
if (overlay == self.targetOverlay) {
//adjustable
annotationView.fillColor = [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:0.3f];
annotationView.strokeColor = [UIColor redColor];
annotationView.lineWidth = 1.0f;
} else {
//fixed
annotationView.fillColor = [UIColor colorWithWhite:0.3f alpha:0.3f];
annotationView.strokeColor = [UIColor purpleColor];
annotationView.lineWidth = 2.0f;
}
return annotationView;
}
return nil;
}
- (void)configureOverlay {
if (self.location) {
[self.mapView removeAnnotations:[self.mapView annotations]];
[self.mapView removeOverlays:[self.mapView overlays]];
CircleOverlay *overlaysmall = [[CircleOverlay alloc] initWithCoordinate:self.location.coordinate radius:100];
[self.mapView addOverlay:overlaysmall];
_targetOverlaySmall = overlaysmall;
CircleOverlay *overlay = [[CircleOverlay alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addOverlay:overlay];
GeoQueryAnnotation *annotation = [[GeoQueryAnnotation alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addAnnotation:annotation];
[self updateLocations];
}
}
Imagine that I have 6 circles. My timer calls first 2 circles in the beginning and overlay them on map view. Then after 2 seconds, it calls other circles and add them on map view. My problem is how to remove previous overlays.I want to see smooth transition for instance radar map.
Make it short, it would like to remove previous overlays and add the new overlays without flickering! Thanks a lot in advance!!.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize mapView;
#synthesize timer;
#synthesize circle1,circle2,circle3,circle4,circle5,circle6;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CLLocationCoordinate2D zoomLocation1;
zoomLocation1.latitude=29.830071;
zoomLocation1.longitude=-95.319099;
circle1 = [MKCircle circleWithCenterCoordinate:zoomLocation1 radius:15000];
circle1.title=#"first level";
CLLocationCoordinate2D zoomLocation2;
zoomLocation2.latitude=29.830071;
zoomLocation2.longitude=-95.319099;
circle2 = [MKCircle circleWithCenterCoordinate:zoomLocation2 radius:4000];
circle2.title=#"first level";
CLLocationCoordinate2D zoomLocation3;
zoomLocation3.latitude=29.830071;
zoomLocation3.longitude=-95.319099;
circle3 = [MKCircle circleWithCenterCoordinate:zoomLocation3 radius:6000];
circle3.title=#"second level";
CLLocationCoordinate2D zoomLocation4;
zoomLocation4.latitude=29.830071;
zoomLocation4.longitude=-95.319099;
circle4 = [MKCircle circleWithCenterCoordinate:zoomLocation4 radius:18000];
circle4.title=#"second level";
CLLocationCoordinate2D zoomLocation5;
zoomLocation5.latitude=29.830071;
zoomLocation5.longitude=-95.319099;
circle5 = [MKCircle circleWithCenterCoordinate:zoomLocation5 radius:1000];
circle5.title=#"third level";
CLLocationCoordinate2D zoomLocation6;
zoomLocation6.latitude=29.830071;
zoomLocation6.longitude=-95.319099;
circle6 = [MKCircle circleWithCenterCoordinate:zoomLocation6 radius:13000];
circle6.title=#"third level";
MKCoordinateRegion viewRegion=MKCoordinateRegionMakeWithDistance(zoomLocation1, 60*1609, 60*1609);
MKCoordinateRegion adjustedRegion=[mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
mapView.mapType=MKMapTypeStandard;
[mapView setDelegate:(id)self];
i=0;
}
- (void)viewDidUnload
{
[self setMapView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)drawButton:(id)sender {
timer = [NSTimer scheduledTimerWithTimeInterval:(2.0) target:self selector:#selector(addingOverlay) userInfo:nil repeats:YES];
}
- (void)addingOverlay {
i=i+1;
switch(i%3)
{
case 1:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle1];
[mapView addOverlay:circle2];
break;
case 2:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle3];
[mapView addOverlay:circle4];
break;
case 3:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle5];
[mapView addOverlay:circle6];
break;
}
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay> )overlay
{
MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay];
if ([overlay.title isEqualToString:#"first level"])
{
circleView.strokeColor = [UIColor redColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor yellowColor];
}
else if([overlay.title isEqualToString:#"second level"])
{
circleView.strokeColor = [UIColor whiteColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor blackColor];
}
else{
circleView.strokeColor = [UIColor greenColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor redColor];
}
return circleView;
}
#end
I just posted this answer to a similar question.
It has a function that I use (drawRangeRings) that draws two circles. In my example, both circles have the same center coordinate, but different radius values, and colors. You could easily change the code to use different center coordinates for each circle if you need that.
Basically, I call drawRangeRings when the center coordinate changes, and it removes the original two circles, and draws two new ones at a different location.
Let me know if this isn't exactly what you needed.
I don't see any flicker when I use this in my app.
Alright, the problem I'm having is that I have an overlay that is driven by the compass heading for the iphone. Whenever the compass heading changes, the line should move across the map with the heading. There are two overlays, one for the compass and another one. When only the compass overlay is being displayed, the line will flicker as it changes, but when the other line is displayed, the flicker goes away and the line moves smoothly.
- (MKOverlayView *)mapView:(MKMapView *)map viewForOverlay:(id <MKOverlay>)overlay
{
SatFinderAppDelegate *appdel = (SatFinderAppDelegate *)[[UIApplication sharedApplication]delegate];
float s = [appdel.location floatValue];
if (overlay == self.headingline)
{
headinglineView = [[MKPolylineView alloc] initWithPolyline:self.headingline];
headinglineView.fillColor = [UIColor greenColor];
headinglineView.strokeColor = [UIColor greenColor];
headinglineView.lineWidth = 5;
return self.headinglineView;
}
if (overlay == self.routeLine)
{
if (s == 0) {
return routeLineView = nil;
}
routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
routeLineView.fillColor = [UIColor cyanColor];
routeLineView.strokeColor = [UIColor cyanColor];
routeLineView.lineWidth = 5;
if (ele < 0) {
routeLineView.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithFloat:12],
[NSNumber numberWithFloat:8],nil];
routeLineView.strokeColor = [UIColor redColor];
}
return routeLineView;
}
return nil;
}
...
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
//line for heading
[self headinglineupdate];
}
....
-(void)headinglineupdate
{
[map removeOverlay:self.headingline];
self.headingline = nil;
self.headingline = [MKPolyline polylineWithCoordinates:locations count:2];
[map addOverlay:headingline];
[headinglineView setNeedsDisplay];
[map setNeedsDisplay];
}