How to bring UIBezierPath to the back of a MKAnnotation object?

前端 未结 1 552
星月不相逢
星月不相逢 2020-12-30 16:03

In my app, user draws a shape on map and using UIBeizerPath i am drawing that path. Then based on the coordinates of the path i am displaying the results which are only in t

相关标签:
1条回答
  • 2020-12-30 16:30

    Apparently, when you add your bezier path to the map via:

            [_mapView.layer addSublayer:shapeLayer];
    

    it is getting added above some internal layer that MKMapView uses to draw the annotations. If you take a look at this somewhat related question, you'll see that you can implement the MKMapViewDelegate protocol, and get callbacks when new station annotations are added. When this happens, you basically inspect the view heirarchy of the newly added annotations, and insert a new, transparent UIView layer underneath them. You take care to bring all the annotations in front of this transparent UIView.

      // always remember to assign the delegate to get callbacks!
      _mapView.delegate = self;
    

    ...

    #pragma mark - MKMapViewDelegate
    
    - (void)mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views{
        if (views.count > 0) {
            UIView* firstAnnotation = [views objectAtIndex:0];
            UIView* parentView = [firstAnnotation superview];
            // NOTE: could perform this initialization in viewDidLoad, too
            if (self.pathOverlay == nil){
                // create a transparent view to add bezier paths to
                pathOverlay = [[UIView alloc] initWithFrame: parentView.frame];
                pathOverlay.opaque = NO;
                pathOverlay.backgroundColor = [UIColor clearColor];
                [parentView addSubview:pathOverlay]; 
            }
    
            // make sure annotations stay above pathOverlay
            for (UIView* view in views) {
                [parentView bringSubviewToFront:view];
            }
        }
    }
    

    Then, instead of adding your shape layer to _mapView.layer, you add it to your transparent view layer, also using this new layer in the coordinate conversion:

    - (void)handleGesture:(UIPanGestureRecognizer*)gesture
    {
        CGPoint location = [gesture locationInView: self.pathOverlay];
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            if (!shapeLayer)
            {
                shapeLayer = [[CAShapeLayer alloc] init];
                shapeLayer.fillColor = [[UIColor clearColor] CGColor];
                shapeLayer.strokeColor = [[UIColor greenColor] CGColor];
                shapeLayer.lineWidth = 5.0;
                [pathOverlay.layer addSublayer:shapeLayer];   // <- change here !!!
            }
            self.path = [[UIBezierPath alloc] init];
            [path moveToPoint:location];
        }
        else if (gesture.state == UIGestureRecognizerStateChanged)
        {
            [path addLineToPoint:location];
            shapeLayer.path = [path CGPath];
        }
        else if (gesture.state == UIGestureRecognizerStateEnded)
        {
            /*
             * This code is the same as what you already have ...
             */
    
                 // But replace this next line with the following line ...
                 //CGPoint loc = [_mapView convertCoordinate:coords toPointToView:self];
                 CGPoint loc = [_mapView convertCoordinate:coords toPointToView: self.pathOverlay];
    
            /*
             * And again use the rest of your original code
             */            
        }
    }
    

    where I also added an ivar (and property) for the new transparent layer:

    UIView* pathOverlay;
    

    I tested this with a bogus grid of stations and got the following results:

    enter image description here

    P.S. I'd also recommend getting rid of your static variables. Just make them ivars/properties of your class.

    0 讨论(0)
提交回复
热议问题