2011-04-15 30 views
19

我試圖用覆蓋圖(MKOverlay)在MKMapView上跟蹤路線。 但是,根據當前速度,如果顏色發生變化(例如,如果用戶從65英里/小時到30英里/小時的駕駛時從綠色變爲橙色),則我想在追蹤路線時使用具有漸變功能的耐克應用。使用MapKit的漸變折線ios

這裏有我想要的截圖:

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; 

基本上我增加了很多小覆蓋。然後,我想創造這個小畫線的坡度,所以我想在覆蓋委託這樣做:

- (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米以上時,我也可以跟蹤路徑。

你能幫我一下,給我提示! 謝謝!

+1

routeLine和routeLineView是如何聲明的?上面的代碼是什麼類? 「不能讓它工作」 - 會發生什麼? – Rayfleck 2011-05-25 21:09:52

+0

我只是看不到我添加到覆蓋視圖中的漸變。 'MKPolyline * routeLine;'和'MKPolylineView * routeLineView;',然後每20米創建一個新的並添加爲覆蓋。在上面的MKMapView委託函數中,我根據標準創建視圖並嘗試向其添加漸變。 – Dachmt 2011-06-17 18:16:43

回答

2

聽起來我的畫線視圖中的drawRect缺少漸變的設置。繪製可能發生在疊加層的不同線程上。請發佈代碼。

+0

請在我的帖子中看到上面的代碼,我更新了它。我有一個功能,每20米添加一個從A點到B點的疊加層,然後當我在地圖視圖委託中創建疊加視圖時,我嘗試添加漸變層。 – Dachmt 2011-06-22 00:20:36

+0

你的邏輯似乎是錯誤的。您不能像這樣向疊加層添加漸變圖層。相反,您必須有一種方法來構建和繪製具有不同陰影的各個分段的整個路徑。有WWDC 2010示例代碼(「Breadcrumbs」)展示了這一點。您目前的方法無法正常工作,因爲您只是第一次將路徑段添加爲新的子層。但是隨着時間的推移,這會導致圖層樹變得非常大。您需要能夠在一個圖層中繪製整個路徑。 – Cocoanetics 2011-06-22 07:27:45

+0

好的,謝謝@Cocoanetics我會看看它,讓你更新! – Dachmt 2011-06-23 00:30:45

13

一個我想出的想法是創建一個CGPath和中風它與梯度每當被稱爲drawMapRect方法時,由於MKPolylineViewMKPlolylineRenderer在ios7取代。

我試圖通過繼承一個MKOverlayPathRenderer來實現這一點,但我沒能挑出個別CGPath,然後我發現一個神祕的方法命名-(void) strokePath:(CGPathRef)path inContext:(CGContextRef)context這聽起來像我所需要的,但如果你不叫就不會被稱爲當你覆蓋你的drawMapRect超級方法。

多數民衆贊成在我現在工作。

我會繼續嘗試,所以如果我解決了一些問題,我會回來並更新答案。

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

enter image description here

所以這是我的工作了,這些天,我幾乎實現上面提到的基本的想法,但,是的,我現在還不能挑根據特定的mapRect繪製一個單獨的PATH,所以當所有路徑的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]; 
} 

這是所有核心繪圖方法,當然你需要pointsvelocity在覆蓋類以及CLLocationManager養活他們。

最後一點是如何得到hue數值超出速度,好吧,我發現如果0.03到0.3之間的色調恰好代表從紅色到綠色,所以我做一些比例映射到色調和速度。

最後的最後,你在這兒這是該演示的全部源:https://github.com/wdanxna/GradientPolyline

如果不能看到你畫的線不要驚慌,我只是定位在我的位置在地圖區域:)

+0

剛看到你的答案。我認爲這正是我需要在這個問題中實現的:http://stackoverflow.com/questions/20247313/gradient-along-mkpolylineview-mk​​polylinerenderer。基本上,如果我理解正確,您將手動逐段重新創建路徑,並通過每次裁剪將梯度僅應用於當前添加的路徑。這是最佳/足夠快嗎? – Templar 2013-12-03 16:37:33

+0

最初,我試圖用一個漸變對象繪製整個路徑,它具有我需要的所有顏色值,並且每個顏色值都映射到我的'gradientLocation'中的一個位置值。我認爲這應該工作,但不是(怪異的)。並且文件說我們不應該從當前的MapRect中抽取任何東西,它似乎像一次繪製完整的路徑不是一種選擇?所以我認爲將其拆分爲細分是最簡單的方法...談論最佳,它在我的iPhone中運行正常:)但仍然有一些改進,如:只繪製與當前MapRect相交的線條。 – wdanxna 2013-12-05 08:15:27

+0

我根據你的代碼和github例子實現了我的東西,並且工作起來非常棒。我建議的改變是直接在init中準備路徑,並在'drawRect'中使用,或者簡單地使用'CGRectpointsR = [self rectForMapRect:polyline.boundingMapRect];'並檢查CGRectContains,不僅用於交集。我的問題仍然沒有答案,並有一個賞金。你可以在上面發表你的答案,我會很高興地接受它,它幫助了我很多:) – Templar 2013-12-05 14:12:58