Domanda

I have created an application that constantly reads the current user coordinates and store them in a SQLite database.
I have a map that is displayed over the whole screen.
And now I want to draw a line over the map while the user moves.
I already created all this.
The problem is that I can't make it to be a 'live'. The Overlay is not updating.
This is the logic:
In ViewDidLoad I have

...
if (nil != self.routeLine) {
        [self.mapView addOverlay:self.routeLine];
    }

In a function that handle each new coordinates I have:

...
NSString* coordinate = [NSString stringWithFormat:@"%f,%f", thisLocation.longitude, thisLocation.latitude];
            [self.paths addObject:coordinate];

MKMapPoint northEastPoint;
    MKMapPoint southWestPoint;

    // create a c array of points.
    MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * self.paths.count);

    for(int idx = 0; idx < self.paths.count; idx++)
    {
        // break the string down even further to latitude and longitude fields.
        NSString* currentPointString = [self.paths objectAtIndex:idx];
        NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];

        CLLocationDegrees latitude  = [[latLonArr objectAtIndex:1] doubleValue];
        CLLocationDegrees longitude = [[latLonArr objectAtIndex:0] doubleValue];

        // create our coordinate and add it to the correct spot in the array
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);


        MKMapPoint point = MKMapPointForCoordinate(coordinate);

        // adjust the bounding box
        // if it is the first point, just use them, since we have nothing to compare to yet.
        if (idx == 0) {
            northEastPoint = point;
            southWestPoint = point;
        }
        else
        {
            if (point.x > northEastPoint.x)
                northEastPoint.x = point.x;
            if(point.y > northEastPoint.y)
                northEastPoint.y = point.y;
            if (point.x < southWestPoint.x)
                southWestPoint.x = point.x;
            if (point.y < southWestPoint.y)
                southWestPoint.y = point.y;
        }

        pointArr[idx] = point;
    }

    // create the polyline based on the array of points.
    self.routeLine = [MKPolyline polylineWithPoints:pointArr count:self.paths.count];

    _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
    // clear the memory allocated earlier for the points
    free(pointArr);

This is viewForOverlay delegate function:

- (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(nil == self.routeLineView)
        {
            self.routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
            self.routeLineView.fillColor = [UIColor blueColor];
            self.routeLineView.strokeColor = [UIColor blueColor];
            self.routeLineView.lineWidth = 5;
        }

        overlayView = self.routeLineView;
    }
    return overlayView;
}
È stato utile?

Soluzione

In viewDidLoad, the code calls addOverlay with self.routeLine which I assume is initially set to the previously-saved coordinates.

The map view adds the MKPoyline that routeLine points to into its internal list of overlays and draws the overlay.

Then, in the "function that handles each new coordinate", self.routeLine is changed to point to a new MKPolyline.

The reason the overlay view is not updated by the map is because the map view is still using the original MKPolyline that was passed to it when addOverlay was called.


Since MKPolyline itself is not mutable (it does not allow one to change the list of points/coordinates after creation), there are two main options:

  • Remove the existing overlay and add a new one with the updated coordinates. This is the simplest option. After setting self.routeLine to a new MKPolyline, do the following (for example):

    [self.mapView removeOverlays:mapView.overlays];
    self.routeLineView = nil;
    [self.mapView addOverlay:self.routeLine];
    

    The main drawback to this simple approach is that the overlay will seem to flicker if the updates are done frequently or if the overlay is large or complex.

  • The alternative is to create a custom overlay and overlay view that are mutable and enabling you to dynamically refresh the overlay more quickly and smoothly.
    Fortunately, Apple has provided a sample app called Breadcrumb which does exactly that.

Altri suggerimenti

Maybe you just forgot to call [self.view setNeedsDisplay]?

UIView docs

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top