Подтвердить что ты не робот

Градиентная полилиния с MapKit ios

Я пытаюсь проследить маршрут на MKMapView с помощью оверлея (MKOverlay). Однако, в зависимости от текущей скорости, я хочу сделать что-то вроде приложения Nike с градиентом, прослеживая маршрут, если цвет меняется (например, от зеленого до оранжевого, если пользователь движется со скоростью 65 миль в час до 30 миль в час).

Вот скриншот того, что я хочу:

gradient overlay image

Итак, каждые 20 метров я добавляю оверлей от старых к новым координатам, используя:

// Create a c array of points. 
MKMapPoint *pointsArray = malloc(sizeof(CLLocationCoordinate2D) * 2);

// Create 2 points.
MKMapPoint startPoint = MKMapPointForCoordinate(CLLocationCoordinate2DMake(oldLatitude, oldLongitude));
MKMapPoint endPoint = MKMapPointForCoordinate(CLLocationCoordinate2DMake(newLatitude, newLongitude));

// Fill the array.
pointsArray[0] = startPoint;
pointsArray[1] = endPoint;

// Erase polyline and polyline view if not nil.
if (self.routeLine != nil)
    self.routeLine = nil;

if (self.routeLineView != nil)
    self.routeLineView = nil;

// Create the polyline based on the array of points.
self.routeLine = [MKPolyline polylineWithPoints:pointsArray count:2];

// Add overlay to map.
[self.mapView addOverlay:self.routeLine];

// clear the memory allocated earlier for the points.
free(pointsArray);

// Save old coordinates.
oldLatitude = newLatitude;
oldLongitude = newLongitude;

В основном я добавляю много маленьких накладок. Затем я хотел бы создать градиент на этом маленьком чертеже линии, поэтому я пытаюсь сделать это в делетете overlay:

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
    MKOverlayView* overlayView = nil;

    if(overlay == self.routeLine) {
        // If we have not yet created an overlay view for this overlay, create it now. 
        if(self.routeLineView == nil) {
            self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];

            if (speedMPH < 25.0) {
                self.routeLineView.fillColor = [UIColor redColor];
                self.routeLineView.strokeColor = [UIColor redColor];
            }
            else if (speedMPH >= 25.0 && speedMPH < 50.0) {
                self.routeLineView.fillColor = [UIColor orangeColor];
                self.routeLineView.strokeColor = [UIColor orangeColor];
            }
            else {
                self.routeLineView.fillColor = [UIColor greenColor];
                self.routeLineView.strokeColor = [UIColor greenColor];
            }

            // Size of the trace.
            self.routeLineView.lineWidth = routeLineWidth;

            // Add gradient if color changed.
            if (oldColor != self.routeLineView.fillColor) {
                CAGradientLayer *gradient = [CAGradientLayer layer];
                    gradient.frame = self.routeLineView.bounds;
                    gradient.colors = [NSArray arrayWithObjects:(id)[oldColor CGColor], (id)[self.routeLineView.fillColor CGColor], nil];
                    [self.routeLineView.layer insertSublayer:gradient atIndex:0];
            }

            // Record old color for gradient.
            if (speedMPH < 25.0)
                oldColor = [UIColor redColor];
            else if (speedMPH >= 25.0 && speedMPH < 50.0)
                oldColor = [UIColor orangeColor];
            else
                oldColor = [UIColor greenColor];
        }

        overlayView = self.routeLineView;
    }

    return overlayView;
}

Я пытаюсь добавить градиент таким образом, но я думаю, что это не способ сделать это, потому что я не могу заставить его работать.

Я также могу отслеживать маршрут каждый раз, когда есть обновление в местоположении пользователя (в делегате объекта местоположения) или как указано выше каждые 20 метров.

Не могли бы вы помочь мне на этом, дав мне советы! Спасибо!

4b9b3361

Ответ 1

Одна из идей, которые я придумала, - создать CGPath и погладить ее с градиентом каждый раз, когда вызывается метод drawMapRect, поскольку MKPolylineView заменяется на MKPlolylineRenderer в ios7.

Я попытался реализовать это путем подкласса MKOverlayPathRenderer, но я не смог выделить отдельную CGPath, тогда я нахожу таинственный метод с именем -(void) strokePath:(CGPathRef)path inContext:(CGContextRef)context, который звучит так, как мне нужно, но он не будет вызываться, t вызовите метод super, когда вы переопределите drawMapRect.

вот что я сейчас разрабатываю.

Я буду продолжать пытаться, если я что-то придумаю, я вернусь и уточню ответ.

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

enter image description here

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

В методе -(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< 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;

Затем я разбил всю точку пути по точке, чтобы нарисовать ее градиент индивидуально. обратите внимание, что массив hues, содержащий значение оттенка, отображающее каждую скорость местоположения.

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

Это все основной метод рисования, и, конечно, вам нужно points, velocity в вашем классе наложения и передать их с помощью CLLocationManager.

Последняя точка заключается в том, как получить значение hue вне скорости, я обнаружил, что если оттенок в диапазоне от 0,03 до 0,3 точно представляет от красного до зеленого, поэтому я делаю некоторое пропорциональное отображение в оттенок и скорость.

последний из последних, вот вы полный источник этой демонстрации: https://github.com/wdanxna/GradientPolyline

не паникуйте, если не видите линию, которую вы рисуете, я просто позиционирую область карты в своей позиции:)

Ответ 2

звучит для меня, что в drawRect на чертеже линии отсутствует настройка градиента. рисунок может появиться в другом потоке для наложений. пожалуйста, напишите код.