【问题标题】:How to draw a MKCircle whose fill color is not solid but an image如何绘制填充颜色不是纯色而是图像的 MKCircle
【发布时间】:2013-01-12 01:28:59
【问题描述】:

我发现了如何在地图注释周围画一个 cricle。 我是这样做的:

     MKCircle *circle = [MKCircle circleWithCenterCoordinate:theCoordinate radius:15000];
     [myMap addOverlay:circle];

 -(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
 {
    MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay];
    circleView.fillColor =[UIColor redColor];

   return circleView;
}

它工作正常,但我想画一个填充颜色不是这样的圆:

【问题讨论】:

    标签: iphone objective-c mkmapview mkoverlay


    【解决方案1】:

    使用 MKCircleRenderer 回答 iOS 7...

    您应该继承 MKCircleRenderer,并覆盖 fillPath:inContext 方法,类似于此问题的公认答案。例如

    @implementation MKGradientCircleRenderer
    
    - (void)fillPath:(CGPathRef)path inContext:(CGContextRef)context
    {
    
        CGRect rect = CGPathGetBoundingBox(path);
    
        CGContextAddPath(context, path);
        CGContextClip(context);
    
        CGFloat gradientLocations[2] = {0.6f, 1.0f};
        // Start color white with 0.25 alpha,
        // End color green with 0.25 alpha
        CGFloat gradientColors[8] = {1.0f, 1.0f, 1.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.25f};
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocations, 2);
        CGColorSpaceRelease(colorSpace);
    
        CGPoint gradientCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
        CGFloat gradientRadius = MIN(rect.size.width, rect.size.height) / 2;
    
        CGContextDrawRadialGradient(context, gradient, gradientCenter, 0, gradientCenter, gradientRadius, kCGGradientDrawsAfterEndLocation);
    
        CGGradientRelease(gradient);
    
    
    }
    

    然后在您的 MKMapView 委托中,实现以下方法...

    -(MKOverlayRenderer *)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay {
    
        MKCircle * circle = (MKCircle *)overlay;
    
        MKGradientCircleRenderer * renderer = [[MKGradientCircleRenderer alloc] initWithCircle:circle];
    
        return renderer;
    
    }
    

    这将允许您实现相同的效果,但使用 iOS 7 中可用的新方法。

    【讨论】:

      【解决方案2】:

      要绘制带有渐变的圆,您必须提供自己的注释视图类,因为现有的都不支持。您可以做的是您可以在MKCircleView 的子类中覆盖方法- (void)fillPath:(CGPathRef)path inContext:(CGContextRef)context。这里有一些代码(未优化,带有硬编码的填充参数)可以帮助您入门:

      @interface TWOGradientCircleView : MKCircleView
      @end
      
      @implementation TWOGradientCircleView
      
      - (void)fillPath:(CGPathRef)path inContext:(CGContextRef)context
      {
          CGRect rect = CGPathGetBoundingBox(path);
      
          CGContextAddPath(context, path);
          CGContextClip(context);
      
          CGFloat gradientLocations[2] = {0.6f, 1.0f};
          // Start color white with 0.25 alpha,
          // End color green with 0.25 alpha
          CGFloat gradientColors[8] = {1.0f, 1.0f, 1.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.25f};
          CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
          CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocations, 2);
          CGColorSpaceRelease(colorSpace);
      
          CGPoint gradientCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
          CGFloat gradientRadius = MIN(rect.size.width, rect.size.height) / 2;
      
          CGContextDrawRadialGradient(context, gradient, gradientCenter, 0, gradientCenter, gradientRadius, kCGGradientDrawsAfterEndLocation);
      
          CGGradientRelease(gradient);
      }
      

      要使用它,只需将MKCircleView 替换为TWOGradientCircleView

      - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
      {
          MKCircleView *circleView = [[TWOGradientCircleView alloc] initWithOverlay:overlay];
      
          return circleView;
      }
      

      如果您想使用图像而不是绘制渐变,可以将上面的渐变绘制替换为图像绘制。由于放大会模糊图像,因此您应该禁用缩放,或者按照 Apple 在 WWDC10 的会话中展示的平铺图像(请参阅 here 以获取带有示例代码的存储库)。使用图案图像设置 UIColor 不适用于 15000 的半径(除非您使用非常非常大的图像;))。

      【讨论】:

      • 您需要将接口 TWOGradientCircleView : MKCircleView 替换为接口 TWOGradientCircleView : MKCircleRenderer 才能在 iOS7+ 上工作(并且 iOS8+ 被明确拒绝使用 MKCircleView)
      【解决方案3】:

      为了在 Swift 2.0 (iOS7+) 中实现该解决方案,我使用了以下解决方案

      import Foundation
      import MapKit
      
      class TWOGradientCircleRenderer: MKCircleRenderer {
      
          override func fillPath(path: CGPath, inContext context: CGContext) {
              let rect:CGRect = CGPathGetBoundingBox(path)
      
              CGContextAddPath(context, path);
              CGContextClip(context);
      
              let gradientLocations: [CGFloat]  = [0.6, 1.0];
              let gradientColors: [CGFloat] = [1.0, 1.0, 1.0, 0.25, 0.0, 1.0, 0.0, 0.25];
              let colorSpace = CGColorSpaceCreateDeviceRGB();
              let gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocations, 2);
      
              let gradientCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
              let gradientRadius = min(rect.size.width, rect.size.height) / 2;
      
              CGContextDrawRadialGradient(context, gradient, gradientCenter, 0, gradientCenter, gradientRadius, .DrawsAfterEndLocation);
          }
      }
      

      在您的 MKMapViewDelegate 中,您需要添加

      func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
              if overlay is MKCircle {
                  let circleRenderer = TWOGradientCircleRenderer(overlay: overlay)
                  return circleRenderer
              } else {
                  return MKOverlayRenderer()
              }
          }
      

      【讨论】:

        【解决方案4】:

        您是否尝试将填充颜色设置为使用[UIColor colorWithPatternImage:] 创建的颜色?

        【讨论】:

        • 这将允许使用模式,但不允许使用问题中显示的渐变。即使您将整个渐变存储为位图图像并说服UIImage 使图案足够大,放大也会导致模糊/像素化叠加,或者需要巨大的叠加图像。
        • 他问的是图像,而不是渐变。 :)
        • :) 在标题中,在文本中是关于画一个圆圈。
        • 这真的取决于@DixieFlatline 来澄清这个问题。
        • 没错。您能否将您的答案澄清为可行的解决方案?我在写答案之前尝试过,但对我没有用。
        【解决方案5】:

        此答案适用于 Swift 3.0 / iOS 10。

        class CircleRenderer: MKCircleRenderer {
            override func fillPath(_ path: CGPath, in context: CGContext) {
                let rect: CGRect = path.boundingBox
                context.addPath(path)
                context.clip()
                let gradientLocations: [CGFloat]  = [0.6, 1.0]
                let gradientColors: [CGFloat] = [1.0, 1.0, 1.0, 0.25, 0.0, 1.0, 0.0, 0.25]
                let colorSpace = CGColorSpaceCreateDeviceRGB()
                guard let gradient = CGGradient(colorSpace: colorSpace, colorComponents: gradientColors, locations: gradientLocations, count: 2) else { return }
        
                let gradientCenter = CGPoint(x: rect.midX, y: rect.midY)
                let gradientRadius = min(rect.size.width, rect.size.height) / 2
                context.drawRadialGradient(gradient, startCenter: gradientCenter, startRadius: 0, endCenter: gradientCenter, endRadius: gradientRadius, options: .drawsAfterEndLocation)
            }
        }
        

        以及覆盖委托方法:

        func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
            let circleRenderer = CircleRenderer(overlay: overlay)
        
            return circleRenderer
        }
        

        工作中的一个例子:

        【讨论】:

          【解决方案6】:

          ** 仅更新答案:

          在 IOS 7 fillPath:inContext 被 MKCircleView 弃用。尝试改用 MKCircleRenderer。

          https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKOverlayPathRenderer_class/Reference/Reference.html#//apple_ref/occ/cl/MKOverlayPathRenderer

          【讨论】:

            猜你喜欢
            • 2011-09-08
            • 2015-03-02
            • 1970-01-01
            • 2015-02-22
            • 2013-02-01
            • 1970-01-01
            • 2019-12-11
            • 2013-07-01
            • 2017-05-20
            相关资源
            最近更新 更多