Поиск мест / местоположений с помощью MapKit и панели поиска (SwiftUI, Xcode 12.4)

#xcode #swiftui #mapkit #mkmapview #xcode12

#xcode #swiftui #mapkit #mkmapview #xcode12

Вопрос:

У меня есть вопрос о том, как можно подключить панель поиска к MapKit, чтобы она могла искать места / местоположения (не используя раскадровку). Я уже написал код для панели поиска и для MapView в отдельных файлах, но даже после того, как я перепробовал буквально каждый код и учебник в Интернете, я не смог найти способ подключить панель поиска для поиска местоположений. Ниже можно увидеть соответственно используемый файл SearchBar.swift, файл MapViewController.swift и фрагмент файла contentView.swift.

Панель поиска.swift

 import UIKit
import Foundation
import SwiftUI
import MapKit

struct SearchBar: UIViewRepresentable {
    // Binding: A property wrapper type that can read and write a value owned by a source of truth.
    @Binding var text: String
    // NSObject: The root class of most Objective-C class hierarchies, from which subclasses inherit a basic interface to the runtime system and the ability to behave as Objective-C objects.
    // UISearchBarDelegate: A collection of optional methods that you implement to make a search bar control functional.
    class Coordinator: NSObject, UISearchBarDelegate {
        
        @Binding var text: String
        let Map = MapViewController()
        
        init(text: Binding<String>) {
            _text = text
        }
        
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
        
        func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        }
        
        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            text = ""
            searchBar.showsCancelButton = true
            searchBar.endEditing(true)
            searchBar.resignFirstResponder()
        }
        
    }
    
    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }
    
    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.showsCancelButton = true
        searchBar.searchBarStyle = .minimal
        //searchBar.backgroundColor = .opaqueSeparator
        searchBar.showsCancelButton = true
        
        return searchBar
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        uiView.text = text
    }
    
}
 

MapViewController.быстрый

 class MapViewController: UIViewController, CLLocationManagerDelegate {
    let mapView = MKMapView()
    let locationManager = CLLocationManager()
    @Published var permissionDenied = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupMapView()
        checkLocationServices()

    }
    
    func setupMapView() {
        view.addSubview(mapView)
        
        mapView.translatesAutoresizingMaskIntoConstraints = false
        mapView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        mapView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
        mapView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
        
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let span = MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005)
        guard let location = locations.last else { return }
        let region = MKCoordinateRegion(center: location.coordinate, span: span)
        mapView.setRegion(region, animated: true)
        let categories:[MKPointOfInterestCategory] = [.cafe, .restaurant]
        let filters = MKPointOfInterestFilter(including: categories)
        mapView.pointOfInterestFilter = .some(filters)
        // Enables the scrolling around the user location without hopping back
        locationManager.stopUpdatingLocation()
    }
    
    func checkLocalAuthorization() {
        switch CLLocationManager.authorizationStatus() {
        case .authorizedWhenInUse:
            mapView.showsUserLocation = true
            followUserLocation()
            locationManager.startUpdatingLocation()
            break
        case .denied:
            permissionDenied.toggle()
            break
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted:
            // Show alert
            break
        case .authorizedAlways:
            break
        @unknown default:
        fatalError()
        }
    }
    
    func checkLocationServices() {
        if CLLocationManager.locationServicesEnabled() {
            setupLocationManager()
            checkLocalAuthorization()
        } else {
            // user did not turn it on
        }
    }
    
    func followUserLocation() {
        if let location = locationManager.location?.coordinate {
            let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 4000, longitudinalMeters: 4000)
            mapView.setRegion(region, animated: true)
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        checkLocalAuthorization()
    }
    
    func setupLocationManager() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error.localizedDescription)
    }
}
 

Затем методы вызываются в файле contentView.swift с использованием следующих методов:

 struct MapViewRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> some UIViewController {
        return MapViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    }
}

struct ContentView: View {
    @State private var searchText : String = ""
    
    
    var body: some View {
        ZStack(alignment: .top) {
            MapViewRepresentable()
                .edgesIgnoringSafeArea(.all)
                .onTapGesture {
                    self.endTextEditing()
            }
            SearchBar(text: $searchText)
        }
    }
}
 

Возможно ли подключить оба, как я объяснил, или есть другой метод, который вы посоветуете? Я действительно надеюсь, что вы, ребята, сможете мне помочь! Заранее спасибо 🙂