【问题标题】:Draw MKPolyline Fill Color绘制 MKPolyline 填充颜色
【发布时间】:2013-02-01 15:21:00
【问题描述】:

我试图在MKPolylineView 上画一个漂亮的MKPolyline。到目前为止一切都很好 - 折线按照我想要的方式绘制,并且在我想要的时候使用以下代码:

[[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;
}

结果我得到了一条纯蓝色的线。然而,我看到的蓝色不是我期望的笔触填充颜色 - 它是笔触颜色的蓝色。使用此方法时没有填充颜色。 为什么不在折线上绘制填充颜色?

在进一步调查之后,我在 Xcode 的 Quick Help 部分中发现了这条信息:

MKPolylineView 类为 MKPolyline 注释对象提供可视化表示。此视图描边由注释表示的路径。 (该类不会填充路径包围的区域。)您可以通过修改继承自 MKOverlayPathView 类的属性来更改路径的颜色和其他绘制属性。

这听起来很荒谬。我必须使用这个类来设置填充颜色,但是我不能使用这个类来绘制填充颜色?考虑到它已经画了笔画,这似乎很奇怪。文档中这个解释的最后一行有点不清楚,但似乎提供了一个答案——我只是很难编码/找到答案。我的项目中没有MKOverlayPathView(那是什么?)但这似乎是解决方案 - 有人知道如何使用它吗?

【问题讨论】:

  • MKPolylineViewMKOverlayPathView 的子类。无论如何,您只想使用MKPolygon(并创建关联的MKPolygonView)而不是MKPolylineMKPolygon 绘制描边和填充。

标签: ios objective-c mkmapview mapkit polyline


【解决方案1】:

如果您想要一种颜色的线条和另一种颜色的填充,请使用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+),它们将处理 MKPolygonMKPolylineMKCircle 覆盖:

// 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;
}

通过这种方式,我可以将这三种类型的叠加层中的任意一种添加到我的地图中,并且可以正确渲染所有这些。

【讨论】:

  • 多边形创建一个封闭的形状,而折线创建一个开放的形状。是否可以在不关闭形状的情况下做到这一点?我想画一条线,有填充和描边,但线用多边形闭合,没有用折线填充..
  • 添加两个叠加层,一个用于填充(一个没有可见笔划/边框的多边形,例如一个清晰的strokeColor),另一个用于开放笔划(一条折线)。
【解决方案2】:

您可以通过实现自己的 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下载代码

我已经使用过它并查看此屏幕截图。

【讨论】:

    【解决方案3】:

    我有另一种方法。

    如果你没有坐标数组,你可以画两条折线。

    绘制特定 line1_width 的第一条线,然后使用 line2_width = line1_width - 1.0 绘制另一条线。

    这将绘制两条线,在第二条线中,您只会看到它的边距,成为第一条线的笔划。

    【讨论】:

      【解决方案4】:

      是的,正如 Rob 提到的,使用 MKPolygon 和 MKPolygonRenderer 而不是 MKPolyline 和 MKPolylineRenderer,但还要确保您的点数组按顺时针顺序排列。如果它是逆时针顺序,你只需要通过在数组上调用 reverse() 来反转它。

      pointsToUse.reverse()
      let overlay = MKPolygon(coordinates: &pointsToUse, count: pointsToUse.count)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多