且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用MapKit ios的渐变折线

更新时间:2022-12-30 13:01:40

我想出的一个想法就是创建一个CGPath并每次用渐变来抚摸它当 drawMapRect 方法被调用时,因为 MKPolylineView MKPlolylineRenderer $ c $替换c>在ios7中。

One of the idea I came up is to create a CGPath and stroke it with gradient every time when drawMapRect method been called, since the MKPolylineView is replaced by MKPlolylineRenderer in ios7.

我试图通过继承 MKOverlayPathRenderer 来实现这个,但是我没有选择单独的CGPath ,然后我找到一个名为的神秘方法 - (void)strokePath:(CGPathRef)路径inContext:(CGContextRef)context 这听起来像我需要的,但它不会被调用如果你在覆盖 drawMapRect 时没有调用super方法。

I tried to implement this by subclassing a MKOverlayPathRenderer but I failed to pick out individual CGPath, then I find a mysterious method named-(void) strokePath:(CGPathRef)path inContext:(CGContextRef)context which sounds like what I need, but it will not be called if you don't call the super method when you override your drawMapRect.

这就是我现在正在努力的事情。

thats what Im working out for now.

我会继续这样做,如果我找到了什么我会回来并更新答案。

I'll keep trying so if I work out something I'll come back and update the answer.

======的更新强> ================================ ================

=========UPDATE================================================

这就是我最近解决的问题,我几乎实现了上面提到的基本思想但是,我仍然无法根据特定的mapRect选择单独的PATH,所以我只是在所有路径的boundingBox与当前mapRect相交时同时绘制所有具有渐变的路径。糟糕的伎俩,但现在工作。

So that is what I'm worked out these days, I almost implemented the basic idea mentioned above but yes, I still cannot pick out an individual PATH according to specific mapRect, so I just draw all paths with gradient at the same time when the boundingBox of all paths intersects with current mapRect. poor trick, but work for now.

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext :( CGContextRef)context render类中的方法,我这样做:

In the -(void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context method in render class, I do this:

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

//merging all the points as entire path
for (int i=0;i< polyline.pointCount;i++){
    CGPoint point = [self pointForMapPoint: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;

然后我逐点拆分整个路径以单独绘制其渐变。
请注意色调数组,其中包含映射每个位置速度的色调值。

Then I split the entire path point by point to draw its gradient individually. note that the hues array containing hue value mapping each velocity of location.

for (int i=0;i< polyline.pointCount;i++){
    CGMutablePathRef path = CGPathCreateMutable();
    CGPoint point = [self pointForMapPoint:polyline.points[i]];
    ccolor = [UIColor colorWithHue:hues[i] saturation:1.0f brightness:1.0f alpha:1.0f];
    if (i==0){
        CGPathMoveToPoint(path, nil, point.x, point.y);
    } else {
        CGPoint prevPoint = [self pointForMapPoint:polyline.points[i-1]];
        CGPathMoveToPoint(path, nil, prevPoint.x, prevPoint.y);
        CGPathAddLineToPoint(path, nil, point.x, point.y);
        CGFloat pc_r,pc_g,pc_b,pc_a,
        cc_r,cc_g,cc_b,cc_a;
        [pcolor getRed:&pc_r green:&pc_g blue:&pc_b alpha:&pc_a];
        [ccolor getRed:&cc_r green:&cc_g blue:&cc_b alpha:&cc_a];
        CGFloat gradientColors[8] = {pc_r,pc_g,pc_b,pc_a,
                                    cc_r,cc_g,cc_b,cc_a};

        CGFloat gradientLocation[2] = {0,1};
        CGContextSaveGState(context);
        CGFloat lineWidth = CGContextConvertSizeToUserSpace(context, (CGSize){self.lineWidth,self.lineWidth}).width;
        CGPathRef pathToFill = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, self.lineCap, self.lineJoin, self.miterLimit);
        CGContextAddPath(context, pathToFill);
        CGContextClip(context);//<--clip your context after you SAVE it, important!
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocation, 2);
        CGColorSpaceRelease(colorSpace);
        CGPoint gradientStart = prevPoint;
        CGPoint gradientEnd = point;
        CGContextDrawLinearGradient(context, gradient, gradientStart, gradientEnd, kCGGradientDrawsAfterEndLocation);
        CGGradientRelease(gradient);
        CGContextRestoreGState(context);//<--Don't forget to restore your context.
    }
    pcolor = [UIColor colorWithCGColor:ccolor.CGColor];
}

这是所有核心绘图方法,当然你需要 velocity 在你的覆盖类中,用CLLocationManager提供它们。

That is all the core drawing method and of course you need points, velocity in your overlay class and feed them with CLLocationManager.

最后一点是如何得到 hue 超出速度的值,嗯,我发现如果0.03~0.3范围内的色调恰好代表从红色到绿色,那么我做一些按比例映射到色调和速度。

the last point is how to get hue value out of velocity, well, I found that if hue ranging from 0.03~0.3 is exactly represent from red to green, so I do some proportionally mapping to hue and velocity.

最后一个,这里是这个演示的完整来源: https://github.com/wdanxna/GradientPolyline

last of the last, here you are this is full source of this demo:https://github.com/wdanxna/GradientPolyline

如果不能不恐慌看到你画的线,我只是将地图区域放在我的位置上:))

don't panic if can't see the line you draw, I just position the map region on my position :)