NetDemo
NetDemo

Reputation: 373

dynamically change lineWidth of mkpolyline

I have Map in my app in which is moving as per user location.I have successfully drawn a polyline for source and destination. Using following code

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id < MKOverlay >)overlay{
    
    MKPolylineView *view1 = [[MKPolylineView alloc] initWithOverlay:overlay];
    
        view1.lineWidth = 27.0;
        view1.strokeColor = [UIColor colorWithRed:55.0/255.0 green:168.0/255.0 blue:219.0/255.0 alpha:1];
   
    return view1;
}

But my problem is when map is moving , mean i am changing region of map as user moves , then some times polyline is not shown good some time its show thicker than actual size as you can see in below image.

i am attaching the image below, please let me know what can i do for smooth polyline when map is moving.

enter image description here

EDIT

As Matt suggested i create a subclass of MKPolylineRenderer and implement drawMapRect method as below:

-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context{
    
    
    CGMutablePathRef fullPath = CGPathCreateMutable();
    BOOL pathIsEmpty = YES;
    
    //merging all the points as entire path
    for (int i=0;i< self.polyline.pointCount;i++){
        CGPoint point = [self pointForMapPoint:self.polyline.points[i]];
        if (pathIsEmpty){
            CGPathMoveToPoint(fullPath, nil, point.x, point.y);
            pathIsEmpty = NO;
        } else {
            CGPathAddLineToPoint(fullPath, nil, point.x, point.y);
        }
    }
    
    //get bounding box out of entire path.
    CGRect pointsRect = CGPathGetBoundingBox(fullPath);
    CGRect mapRectCG = [self rectForMapRect:mapRect];
    //stop any drawing logic, cuz there is no path in current rect.
    if (!CGRectIntersectsRect(pointsRect, mapRectCG))return;
    
    UIColor *darker = [UIColor blackColor];
    CGFloat baseWidth = 10 / zoomScale;
    
    // draw the dark colour thicker
    CGContextAddPath(context, self.path);
    CGContextSetStrokeColorWithColor(context, darker.CGColor);
    CGContextSetLineWidth(context, baseWidth * 1.5);
    CGContextSetLineCap(context, self.lineCap);
    CGContextStrokePath(context);
    
    // now draw the stroke color with the regular width
    CGContextAddPath(context, self.path);
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, baseWidth);
    CGContextSetLineCap(context, self.lineCap);
    CGContextStrokePath(context);
    
    [super drawMapRect:mapRect zoomScale:zoomScale inContext:context];
}

But Same problem See below image:

enter image description here

ok, i think i got problem , my polyline is added once, but as user's speed i changing zoom level of MKMapView, zoom level is changed , but polyline width is not refresh,

SO how can i dynamically change lineWidth of mkpolyline ??

Upvotes: 8

Views: 4361

Answers (3)

Gwendal Rou&#233;
Gwendal Rou&#233;

Reputation: 4044

Subclass MKPolylineRenderer and override applyStrokePropertiesToContext:atZoomScale: so that it ignores the scale, and draws lines at constant width:

@interface ConstantWidthPolylineRenderer : MKPolylineRenderer
@end

@implementation ConstantWidthPolylineRenderer

- (void)applyStrokePropertiesToContext:(CGContextRef)context
                           atZoomScale:(MKZoomScale)zoomScale
{
    [super applyStrokePropertiesToContext:context atZoomScale:zoomScale];
    CGContextSetLineWidth(context, self.lineWidth);
}

@end

Now use it and admire its smooth rendering:

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    MKPolyline *polyline = (MKPolyline *)overlay;
    ConstantWidthPolylineRenderer *renderer = [[ConstantWidthPolylineRenderer alloc] initWithPolyline:polyline];
    renderer.strokeColor = [UIColor redColor];
    renderer.lineWidth = 40;
    return renderer;
}

Upvotes: 2

matt
matt

Reputation: 534885

The problem is that you are setting your lineWidth at a fixed width (a really big fixed width). This gets larger or smaller as the map is zoomed larger or smaller.

Instead, implement your own MKOverlayRenderer subclass, and override drawMapRect:zoomScale:inContext:. It receives a zoomScale parameter, and so you can adjust the width of your line to look good at what the current scale may be.

Upvotes: 2

Mehul Patel
Mehul Patel

Reputation: 23053

You need to use MKPolylineRenderer instead of MKPolylineView

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay {
    @try {

        MKPolylineRenderer *renderer = [[[MKPolylineRenderer alloc] initWithOverlay:overlay];
        renderer.lineWidth = 27.0;
        renderer.strokeColor = [UIColor colorWithRed:55.0/255.0 green:168.0/255.0 blue:219.0/255.0 alpha:1];

        return renderer;
    }
    @catch (NSException *exception) {
        NSLog(@"exception :%@",exception.debugDescription);
    }
}

Read this one:

The MKPolylineRenderer class provides the visual representation for an MKPolyline overlay object. This renderer strokes the line only; it does not fill it. You can change the color and other drawing attributes of the polygon by modifying the properties inherited from the parent class. You typically use this class as is and do not subclass it.

From Apple library

The MKPolylineView class provides the visual representation for an MKPolyline annotation object. This view strokes the path represented by the annotation. (This class does not fill the area enclosed by the path.) You can change the color and other drawing attributes of the path by modifying the properties inherited from the MKOverlayPathView class. This class is typically used as is and not subclassed.

From Apple library

Upvotes: 1

Related Questions