Home > Back-end >  how to programmatically get new region as Map moves so I can refresh annotations? (swiftui)
how to programmatically get new region as Map moves so I can refresh annotations? (swiftui)

Time:02-06

I have a map with fixed annotations, the annotations change only if I filter the results with a function

I'd like to recalculate the region as user moves the map and show the FILTERED results that match that location (get new region coordinates, then call my getListingsFiltered function)

how can I get the region coordinates when the map changes? I have seen I can use region.center for the move without zoom and regin.span for zoom in/out) but I couldn't make it work.

I've seen also that other answers change region based on change of results, but in my case it's the contrary, I want to change results based on change of map location.

my map enter image description here

desired result (zillow) enter image description here

Map

Map(coordinateRegion: self.$region,annotationItems: model.listingsFZ!) { listing in
                    MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: listing.latitude ?? 0, longitude: listing.longitude ?? 0)) {
                        NavigationLink {
                            ListingDetailView(listing: listing)
                          } label: {
                              PlaceAnnotationView(title: listing.priceShort ?? "")
                          }
                    }
                }
                .onDisappear {
                    model.clear()
                }

Function

    func getListingsFiltered(location: String, PriceMin: String, PriceMax: String, Bedrooms: Int) {
        
        var listingsF = [ListingsZillow]() //new array instance of listing
        
        var regionSearch = self.region
        
        var lowestPrice = 0
        var highestPrice = 1000000000
        
        if PriceMin == "Any" {lowestPrice = 0} else {lowestPrice = Int(PriceMin) ?? 0}
        if PriceMax == "Any" {highestPrice = 1000000000} else { highestPrice = Int(PriceMax) ?? 1000000000}
        
        //append the ones that match
        for listing in self.listingsZ! {
            
            //no region selected
            if regionSearch.center.latitude == 0 || regionSearch.center.longitude == 0 {
                if listing.price! >= lowestPrice && listing.price! <= highestPrice {
                     **some code**
                }
            } else {
                //there is a regionselected
                if listing.latitude != nil {
                    
                    let listingRegion = CLLocationCoordinate2D(latitude: listing.latitude, longitude: listing.longitude)
                    
                    if self.checkRegion(location: regionSearch.center, contains: listingRegion, with: 1000){
                        
                        //condition price
                        if listing.price! >= lowestPrice && listing.price! <= highestPrice {
                            //condition bedrooms
                            if listing.bedrooms! >= Bedrooms {
                                //condition location
                                
                                var l = ListingsZillow()
                                l.address = listing.address!
                                
                                l.bedrooms = listing.bedrooms
                                l.bathrooms = listing.bathrooms
                                l.price = listing.price
                                l.yearBuilt = listing.yearBuilt
                                l.longitude = listing.longitude
                                l.latitude = listing.latitude
                                l.homeStatus = listing.homeStatus
                                l.description = listing.description
                                l.livingArea = listing.livingArea
                                l.url = listing.url
                                l.photos = listing.photos
                                l.priceShort = listing.priceShort
                                
                                listingsF.append(l)
                            }
                        }
                    }
                }
                
            } 
               
        }
        
        DispatchQueue.main.async {
            //self.listingsF = listingsF
            self.listingsFZ = listingsF
            self.filters = true
            
        }
    }

CodePudding user response:

It can be done with the span in the region.

extension CLLocationCoordinate2D{
    ///Check if the `coordinate` is within the `MKCoordinateRegion`
    func isWithinRegion(region: MKCoordinateRegion) -> Bool{
        var result = false
        //Get the upper and lower bounds of the latitude and longitude
        //center  /- span/2
        //divide by 2 because the center is half way through
        let latUpper = region.center.latitude   region.span.latitudeDelta/2
        let latLower = region.center.latitude - region.span.latitudeDelta/2
        let lonUpper = region.center.longitude   region.span.longitudeDelta/2
        let lonLower = region.center.longitude - region.span.longitudeDelta/2
        //If the coordinate is within the latitude and the longitude
        if self.latitude >= latLower && self.latitude <= latUpper{
            if self.longitude >= lonLower && self.longitude <= lonUpper{
                //It is within the region
                result = true
            }
        }
        
        return result
    }
}

If you add the code above to your project you can use something like

listing.coordinate.isWithinRegion(region: regionSearch)

in your filter.

The function will return true if the coordinate is within the region

You can dynamically set the annotations by using a computed variable

///Returns the  `visibleAnnotations` that are within the `region`
var visibleAnnotations: [ListingAnnotation]{
    //Your filter code 
    model.listingsZ.filter({
        $0.coordinate.isWithinRegion(region: region)
    })
}

Or just hide the listings if the operation is time-consuming

NavigationLink{}
    .opacity(listing.coordinate.isWithinRegion(region: vm.region) ? 1 : 0)
    .animation(.easeIn(duration: 1), value: listing.coordinate.isWithinRegion(region: vm.region))
  •  Tags:  
  • Related