Why is drawRect on MKOverlayRenderer slow

落花浮王杯 提交于 2020-01-15 04:50:10

问题


For an app, I have to place a MKCircle annotation on a MKMapView. However, the circle needs to be moved/resized. I know this has been asked, e.g. Moving MKCircle in MKMapView where removing/adding the annotation is suggested to get that behavior.

However, I consider the drawing being very slow, like the user in this post: Smooth resizing of MKCircle. Since there are now answers to this question, the question seemed to use YHAnimatedCircleView. By slow I mean, when I use a UISlider to change the radius of the circle, the redrawing is sloppy and I can also notice the tiles being used to draw it.

I created a small test code, overriding drawMapRect of a subclasses MKOverlayRenderer. The code is as follows:

-(void) drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)context
{
    MKCircle* circleOverlay = (MKCircle*)self.overlay;

    CLLocationCoordinate2D point = circleOverlay.coordinate;          

    CGPoint locationPoint =
        [self pointForMapPoint:MKMapPointForCoordinate(point)];

    CGFloat radius =
        MKMapPointsPerMeterAtLatitude(circleOverlay.coordinate.latitude) *
        circleOverlay.radius;

    CGRect circleRect = CGRectMake(locationPoint.x - radius,
                                   locationPoint.y - radius,
                                   radius * 2.0, radius * 2.0);

    CGContextSaveGState(context);    

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextFillEllipseInRect(context, circleRect);

    CGContextRestoreGState(context);
}

When I move the UISlider the old annotation is removed and the new MKCircle with different radius is placed and the drawMapRect method gets called.

However, even this small example shows sloppy drawing when resizing the circle.

Questions:

  1. Is the above example entirely correct or am I doing something wrong with drawing?
  2. If the example is correct, why is the redrawing of the circle when resizing it so slow/sloppy?

回答1:


I had a similar issue with drawing an overlay on an MKMapView, my issue was moving the circle I had drawn in relation to the map. This was causing a issue with there being lag in the movement of the map compared to the movement in the circle, looking as though the circle was gliding on top of the map as opposed to being fixed on the map.

My solution was to use a CADisplayLink in order to synchronise the drawing of the MKMapView and any views I had added to it. I believe this would work with your original implementation of changing the radius of the circle using a UISlider, however without the implementation, I can't thoroughly test this.

A code example is like this:

- (void)viewDidLoad {
    self.mapUpdateLink = [CADisplayLink displayLinkWithTarget:self
                                                 selector:@selector(updateMapView)];
    [self.mapUpdateLink addToRunLoop:[NSRunLoop mainRunLoop]
                             forMode:NSRunLoopCommonModes];
}

- (void)updateMapView {
    CGPoint centerPoint = [self.mapView convertCoordinate:self.circleView.centerCoordinate
                                            toPointToView:self.view];
    if (!isnan(centerPoint.x) && !isnan(centerPoint.y)) {
        self.circleView.center = centerPoint;
    }
}

I hope this helps you with your issue.




回答2:


As far as I know drawRect in a MKMapView is extremely slow. (As a curiosity people that made CCHMapClusterController also found out that)

What I would do is generate an UIImage instead of doing draw rect:

UIImage *circle;

CGRect circleRect = CGRectMake(locationPoint.x - radius,
                               locationPoint.y - radius,
                               radius * 2.0, radius * 2.0);

UIGraphicsBeginImageContextWithOptions(CGSizeMake(radius * 2.0, radius * 2.0), NO, 0.0f);

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);



CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextFillEllipseInRect(context, circleRect);

CGContextRestoreGState(ctx); 
  circle = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

You can generate that image in layoutSubViews in an AnnotationView (much like the link shows :)). That AnnotationView could have a radius and the UISlider would change the radius. In your setRadius property you call setNeedsLayout.



来源:https://stackoverflow.com/questions/25750758/why-is-drawrect-on-mkoverlayrenderer-slow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!