Нарисовать цвет заливки MKPolyline

Я пытаюсь нарисовать красивый MKPolyline на MKPolylineView. Пока все идет отлично — полилиния рисуется так, как я хочу, и когда я хочу, используя следующий код:

[[self map] addOverlay:routeLine];

И этот метод, чтобы сообщить приложению, как его рисовать:

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
    MKOverlayView* overlayView = nil;
    self.routeLineView = [[MKPolylineView alloc] initWithPolyline:[self routeLine]];
    [[self routeLineView] setFillColor:[UIColor colorWithRed:167/255.0f green:210/255.0f blue:244/255.0f alpha:1.0]];
    [[self routeLineView] setStrokeColor:[UIColor colorWithRed:0/255.0f green:136/255.0f blue:255/255.0f alpha:1.0]];
    [[self routeLineView] setLineWidth:15.0];
    [[self routeLineView] setLineCap:kCGLineCapRound];
    overlayView = [self routeLineView];
    return overlayView;
}

В результате я получаю сплошную синюю линию. Однако синий, который я вижу, не является цветом заливки с обводкой, которую я ожидаю, - это синий цвет обводки. Когда я использую этот метод, цвет заливки отсутствует. Почему не отображается цвет заливки полилинии?

После дальнейшего изучения я нашел этот лакомый кусочек информации в разделе Quick Help Xcode:

Класс MKPolylineView обеспечивает визуальное представление объекта аннотации MKPolyline. Этот вид обводит путь, представленный аннотацией. (Этот класс не заполняет область, ограниченную путем.) Вы можете изменить цвет и другие атрибуты рисования пути, изменив свойства, унаследованные от класса MKOverlayPathView.

Это просто смешно звучит. Мне нужно использовать этот класс для установки цвета заливки, но я не могу использовать этот класс для отрисовки цвета заливки? Это кажется очень странным, учитывая, что он уже рисует штрих. Последняя строка в этом объяснении из документации немного неясна, но, кажется, дает ответ - мне просто трудно кодировать/находить ответ. В моем проекте нет MKOverlayPathView (что это вообще такое?), но кажется, это решение — кто-нибудь знает, как его использовать?


person Sam Spencer    schedule 16.02.2013    source источник
comment
MKPolylineView является подклассом MKOverlayPathView. Независимо от этого, вы просто хотите использовать MKPolygon (и создать связанный MKPolygonView) вместо MKPolyline. MKPolygon рисует и обводку, и заливку.   -  person Rob    schedule 17.02.2013


Ответы (4)


Если вам нужна линия одного цвета, а заливка другого, используйте MKPolygon вместо MKPolyline. Поэтому измените исходное создание аннотации соответствующим образом. Затем вы модифицируете свой viewForOverlay (или, для iOS 7, rendererForOverlay), чтобы распознать MKPolygon, и делаете что-то вроде следующего:

// for iOS7+; see `viewForOverlay` for earlier versions

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {
        MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];

        renderer.fillColor   = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        renderer.lineWidth   = 3;

        return renderer;
    }

    return nil;
}

// for iOS versions prior to 7; see `rendererForOverlay` for iOS7 and later

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {
        MKPolygonView *overlayView = [[MKPolygonView alloc] initWithPolygon:overlay];

        overlayView.fillColor      = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        overlayView.strokeColor    = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth      = 3;

        return overlayView;
    }

    return nil;
}

Обратите внимание, что вам не нужно ссылаться здесь ни на какие свойства вашего класса, так как оверлей передается вашему viewForOverlay. Это немного более гибко, если вы когда-либо добавляли на карту несколько наложений.


Кстати, это мои стандартные viewForOverlay (версии iOS до 7.0) и rendererForOverlay (iOS 7+), которые будут обрабатывать оверлеи MKPolygon, MKPolyline и MKCircle:

// for iOS7+; see `viewForOverlay` for earlier versions

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {
        MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];

        renderer.fillColor   = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        renderer.lineWidth   = 3;

        return renderer;
    }

    if ([overlay isKindOfClass:[MKCircle class]])
    {
        MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:overlay];

        renderer.fillColor   = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        renderer.lineWidth   = 3;

        return renderer;
    }

    if ([overlay isKindOfClass:[MKPolyline class]])
    {
        MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];

        renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        renderer.lineWidth   = 3;

        return renderer;
    }

    return nil;
}

// for iOS versions prior to 7; see `rendererForOverlay` for iOS7 and later

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {
        MKPolygonView *overlayView = [[MKPolygonView alloc] initWithPolygon:overlay];

        overlayView.fillColor      = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        overlayView.strokeColor    = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth      = 3;

        return overlayView;
    }

    if ([overlay isKindOfClass:[MKCircle class]])
    {
        MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:overlay];

        overlayView.fillColor     = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        overlayView.strokeColor   = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth     = 3;

        return overlayView;
    }

    if ([overlay isKindOfClass:[MKPolyline class]])
    {
        MKPolylineView *overlayView = [[MKPolylineView alloc] initWithPolyline:overlay];

        overlayView.strokeColor     = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth       = 3;

        return overlayView;
    }

    return nil;
}

Таким образом, я могу добавить на свою карту как можно больше из этих трех типов наложений, и все они будут правильно отображаться.

person Rob    schedule 16.02.2013
comment
Многоугольник создает замкнутую форму, а полилиния создает открытую форму. Можно ли это сделать, не закрывая форму? Я хочу, чтобы линия была нарисована с заливкой и обводкой, но линия закрывается многоугольником и не имеет заливки полилинией. - person Sti; 08.10.2019
comment
Добавьте два наложения: одно для заливки (многоугольник без видимой обводки/границы, например, прозрачная strokeColor), а другое — для открытой обводки (ломаная линия). - person Rob; 08.10.2019

Вы можете сделать это, реализовав свой собственный подкласс MKOverlayPathView, который дважды рисует путь в прямоугольнике карты. Один раз толще с черным и один раз тоньше сверху с другим цветом.

Я создал простую замену MKPolylineView, которая позволяет вам это сделать: ASPolylineView.

- (void)drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)context
{
    UIColor *darker = [UIColor blackColor];
    CGFloat baseWidth = self.lineWidth / 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, self.strokeColor.CGColor);
    CGContextSetLineWidth(context, baseWidth);
    CGContextSetLineCap(context, self.lineCap);
    CGContextStrokePath(context);

    [super drawMapRect:mapRect zoomScale:zoomScale inContext:context];
}

- (void)createPath
{
    // turn the polyline into a path

    CGMutablePathRef path = CGPathCreateMutable();
    BOOL pathIsEmpty = YES;

    for (int i = 0; i < self.polyline.pointCount; i++) {
        CGPoint point = [self pointForMapPoint:self.polyline.points[i]];

        if (pathIsEmpty) {
            CGPathMoveToPoint(path, nil, point.x, point.y);
            pathIsEmpty = NO;
        } else {
            CGPathAddLineToPoint(path, nil, point.x, point.y);
        }
    }

    self.path = path;
}

Или вы можете скачать код для него по ссылке ниже https://github.com/nighthawk/ASPolylineView.

Я использовал его и посмотрите на этот снимок экрана.

Цвет границы полилинии

person Chandni - Systematix    schedule 10.03.2017

У меня есть другой метод.

Если у вас нет массива координат, вы можете нарисовать две полилинии.

Нарисуйте первую строку вашей конкретной ширины line1_width, а затем нарисуйте другую строку с помощью line2_width = line1_width - 1.0.

Это нарисует две линии, и от второй строки вы увидите только ее границу, которая станет штрихом для первой строки.

person Teodor Ciuraru    schedule 28.05.2014

Да, как упоминал Роб, используйте MKPolygon и MKPolygonRenderer вместо MKPolyline и MKPolylineRenderer, но также убедитесь, что ваш массив точек находится в порядке по часовой стрелке. Если это в порядке против часовой стрелки, вам просто нужно изменить его, вызвав reverse() в массиве.

pointsToUse.reverse()
let overlay = MKPolygon(coordinates: &pointsToUse, count: pointsToUse.count)
person Mike Onorato    schedule 18.10.2016