iosswiftmkmapviewmkcircle

iOS -Adding and Removing MKCircle Overlay to MapView causing glitch


I have a MapView and the user can select a radius to show an area. I add a MKCircle as an overlay. When the radius changes from 30 miles to 1 mile there is a noticeable glitch on the perimeter of the MKCircle while the MapView zooms in. The glitch looks sort of like a flair. It only happens when zooming in and not zooming out.\

Since the zoom constantly changes I remove the old overlay before adding another one but I don't think that's the issue.

How can I remove the glitch on the circle as the MapView's zoom changes?

@IBAction func newRadiusButtonTapped(sender: UIButton) {

    // coordinate is the users location and span was 10 miles now it's 1 mile
    let region = MKCoordinateRegionMake(location.coordinate, span)
    mapView.setRegion(region, animated: true)

    let circle = MKCircle(center: location.coordinate, radius: radius)

     // remove old overlay before adding another one
     for overlay in mapView.overlays {
         mapView.remove(overlay)
     }

     view.layoutIfNeeded()
     // mapView.layoutIfNeeded() I tried this but it didn't make a difference
     mapView.add(circle)
}

30 miles

glitch

1 mile


Solution

  • I couldn't find what was causing the glitch but I found this delegate method from this answer on the mapView that gets notified after the mapView region finishes changing. I add the overlay there

    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { 
    }
    

    Simple process:

    I create a circle property of type MKCircle? I also create property named shouldAddCircle of type Bool and set it to true. When the button is pressed I initial the circle property with the MKCircle that I create inside the button and set the shouldAddCircle to true. Inside the button function I remove all the mapViews overlays.

    Inside the delegate method I now check to see that the shouldAddCircle property is true and if it is I then check to see make sure the circle property isn't nil. If they match then I add the initialized circle to the mapView. After I add the circle to the mapView I have to set the shouldAddCircle to false because every time the user scrolls the map regionDidChangeAnimated gets called and it will keep adding overlays to the map.

    Here' the code below. Be sure to add mapView.delegate = self in viewDidLoad and to set the MKMapViewDelegate before everything.

    var circle: MKCircle?
    var shouldAddCircle = true
    
    @IBAction func newRadiusButtonTapped(sender: UIButton) {
    
        // coordinate is the users location and span was 10 miles now it's 1 mile
        let region = MKCoordinateRegionMake(location.coordinate, span)
        mapView.setRegion(region, animated: true)
    
        let circle = MKCircle(center: location.coordinate, radius: radius)
    
        // set the circle property to match the circle that was just created
        self.circle = circle
    
        // set this true
        shouldAddCircle = true
    
        // remove old overlay before adding another one
        for overlay in mapView.overlays {
            mapView.remove(overlay)
        }
    }
    
    // this function gets called repeatedly as the mapView is zoomed and/or panned
    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    
        // make sure this is true because that means the user updated the radius
        if shouldAddCircle {
    
           // make sure the circle isn't ni
           if let circle = self.circle {
               // after the mapView finishes add the circle to it
               mapView.add(circle)
    
               // set this to false so that this doesn't called again until the user presses the button where they set it to true
               shouldAddCircle = false
           }
        }
    }