Gradient Polyline con MapKit ios

Estoy intentando rastrear una ruta en un MKMapView usando superposiciones (MKOverlay). Sin embargo, dependiendo de la velocidad actual, quiero hacer algo como la aplicación Nike con un degradado mientras trazo la ruta, si el color está cambiando (por ejemplo, de verde a naranja si un usuario está manejando de 65 mph a 30 mph).

Aquí hay una captura de pantalla de lo que quiero:

imagen de superposición de degradado

Entonces, cada 20 metros, agrego una superposición de las coordenadas antiguas a las nuevas usando:

// Create ac 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; 

Básicamente estoy agregando muchas superposiciones pequeñas. Entonces me gustaría crear el degradado en este pequeño dibujo lineal, así que estoy tratando de hacerlo en el delegado de superposición:

 - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )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 && 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 && speedMPH < 50.0) oldColor = [UIColor orangeColor]; else oldColor = [UIColor greenColor]; } overlayView = self.routeLineView; } return overlayView; } 

Estoy tratando de agregar el gradiente de esta manera, pero supongo que no es la forma de hacerlo porque no puedo hacerlo funcionar.

También puedo rastrear la ruta cada vez que hay una actualización en la ubicación del usuario (en el delegado del objeto de ubicación), o como se ve arriba cada 20 metros.

¿Puedes ayudarme por eso, dándome consejos? ¡Gracias!

Una de las ideas que surgió es crear un CGPath y aplicarle un degradado cada vez que se drawMapRect método drawMapRect , ya que MKPolylineView se reemplaza por MKPlolylineRenderer en ios7.

Intenté implementar esto al MKOverlayPathRenderer una subclase de MKOverlayPathRenderer pero no pude seleccionar un CGPath individual, entonces encuentro un misterioso método llamado -(void) strokePath:(CGPathRef)path inContext:(CGContextRef)context que suena como lo que necesito, pero no se invocará si no llamas al súper método cuando anulas tu drawMapRect .

eso es lo que estoy trabajando por ahora.

Seguiré intentándolo, así que si encuentro algo, volveré y actualizaré la respuesta.

========= ACTUALIZACIÓN ===================================== ========

enter image description here

Así que eso es lo que he resuelto estos días, casi implementé la idea básica mencionada anteriormente, pero sí, todavía no puedo elegir un PATH individual de acuerdo con el mapRect específico, así que dibujé todos los caminos con gradiente al mismo tiempo cuando el boundingBox de todos los caminos intersecta con mapRect actual. pobre truco, pero trabaja por ahora.

En el -(void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context método de -(void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context en la clase de representación, hago esto:

 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; 

Luego dividí la ruta completa punto por punto para dibujar su gradiente individualmente. tenga en cuenta que la matriz de hues contiene el valor de tono mapear cada velocidad de ubicación.

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

Ese es todo el método de dibujo central y, por supuesto, necesitas points , velocity en tu clase de superposición y alimentarlos con CLLocationManager.

el último punto es cómo sacar el valor de hue de la velocidad, bueno, encontré que si el tinte que va desde 0.03 ~ 0.3 representa exactamente desde el rojo al verde, entonces hago un mapeo proporcional de tono y velocidad.

último de los últimos, aquí está esta es la fuente completa de esta demostración: https://github.com/wdanxna/GradientPolyline

no se asuste si no puede ver la línea que dibuja, solo coloco la región del mapa en mi posición 🙂

me suena que su drawRect en la vista de dibujo de línea no tiene la configuración del degradado. el dibujo puede ocurrir en un hilo diferente para las superposiciones. por favor publique el código.