9
votes

How can I achieve a smooth resizing of a MKCircleView on a UIMapView when adjusting an NSSlider? Apple has managed to do it in the Find my friends app when creating geofences (http://reviewznow.com/wp-content/uploads/2013/03/find-my-friends-location-alerts-01.jpg), so I guess it's possible in some way. So far I've tried the following solutions, but with a very "flickery" result:

First attempt

I added a new MKCircleView with an updated radius and immediately after removing the one that was (as suggested here MKOverlay not resizing smoothly) when the slider changed value. I also tried the other way around: first removing the overlay then adding a new one, but with the same "flickery" result.

- (void)sliderChanged:(UISlider*)sender
{
    double radius = (sender.value * 100);
    [self addCircleWithRadius:radius];
    [mapView removeOverlays:[self.mapView.overlays firstObject]];
}

Second attempt

In the linked SO answer, he suggests that NSOperation could be used to "help you create the MKCircle objects faster" and thus making the resizing smoother using the above method of adding/removing overlays when the slides changes value. I did a implementation where I start a new thread whenever the slider changes. In each thread I remove all old overlays and add a new one with the updated scale. Perhaps he has some other kind of implementation in mind, because the way I did it I still get the same flicker when changing the slider.

- (void)sliderChanged:(UISlider*)sender
{
     NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                             selector:@selector(updateOverlayWithScale:)
                                                                               object:[NSNumber numberWithFloat:sender.scale]];
     [self.queue addOperation:operation];
}

The method that runs i each thread:

- (void)updateOverlayWithScale:(NSNumber *)scale
{
    MKCircle *circle = [MKCircle circleWithCenterCoordinate:self.currentMapPin.coordinate
                                                     radius:100*[scale floatValue]];


    [self.mapView performSelectorOnMainThread:@selector(removeOverlays:) withObject:self.mapView.overlays waitUntilDone:NO];
    [self.mapView performSelectorOnMainThread:@selector(addOverlay:) withObject:circle waitUntilDone:NO];
}

Third attempt

I also tried implementing my own subclass of MKOverlayView that draws itself based on its scale property. Whenever the slider changes I call setNeedsDisplay and let it redraw itself, but I get the same flicker.

- (void)sliderChanged:(UISlider*)sender
{
     self.currentOverlayView.scale = sender.scale
     [self.currentOverlayView setNeedsDisplay];
}

And in my custom overlay view I implement drawMapRect:zoomScale:inContext:(CGContextRef)context like this

- (void)drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)context
{
     double radius = [(MKCircle *)[self overlay] radius];
     radius *= self.scale;

     // ... Create a rect using the updated radius and draw a circle inside it using CGContextAddEllipseInRect ...

}

So, do you have any ideas? Thanks in advance!

1
I'm struggling with this too, how did you do it?Adam Waite

1 Answers

0
votes

A few months ago I stumbled upon this animated MKCircleView. It also has a demo on git. So I guess you should give it a go! Check it out as you might be able to tweak it to your needs with a slider etc.

Credits go to yickhong for providing this YHAnimatedCircleView