dev._.note

[Swift] MapKit으로 사용자 중심의 장소설정 본문

Dev/SWIFT

[Swift] MapKit으로 사용자 중심의 장소설정

Laena 2024. 2. 27. 21:24
투두리스트에서 위치알람을 주기 위해 '장소'설정을 하려고 하는데 어떤 식으로 구현을 할까 고민하다가 카카오택시에서 중앙핀을 기준으로 중앙 좌표값을 주는 것을 보고 사용자가 장소를 직관적으로 설정할 수 있겠다 싶어서 카카오 택시 앱을 참고해서 사용자가 손쉽게 위치값을 설정할 수 있게 구현하고자 했습니다.

 

mapView(_:regionDidChangeAnimated:) 메소드

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    let center = mapView.centerCoordinate
    getAddressFromCoordinates(center)
}
  • 지도 뷰의 영역이 변경될 때 호출됩니다. 지도의 중심 좌표를 가져와서 해당 좌표에서 주소를 검색합니다.

 

마커핀 표시

// centerPin
centerPin.snp.makeConstraints { make in
	make.center.equalToSuperview()
	make.width.equalTo(30)
	make.height.equalTo(60)
}
centerPin.contentMode = .scaleAspectFit

 


전체코드

import UIKit

import MapKit
import CoreLocation
import SnapKit

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UISearchBarDelegate {
    
    let mapView = MKMapView()
    let locationManager = CLLocationManager()
    let geocoder = CLGeocoder()
    let centerPin = UIImageView(image: UIImage(named: "pin"))
    let searchBar = UISearchBar()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupMapView()
        configureLayout()
        setupSearchBar()
        centerMapOnUserLocation()
        setupUserTrackingButton()
    }

    private func setupMapView() {
        view.addSubview(mapView)
        mapView.delegate = self
        mapView.showsUserLocation = true
        
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        
        view.addSubview(centerPin)
    }
    
    private func setupUserTrackingButton() {
        let userTrackingButton = MKUserTrackingButton(mapView: mapView)
        userTrackingButton.backgroundColor = UIColor(white: 1, alpha: 0.8)
        userTrackingButton.layer.cornerRadius = 20
        userTrackingButton.layer.masksToBounds = true
        view.addSubview(userTrackingButton)

        userTrackingButton.snp.makeConstraints { make in
            make.bottom.equalToSuperview().inset(20)
            make.right.equalToSuperview().inset(20)
            make.width.height.equalTo(40)
        }
    }

    private func configureLayout() {
        // mapView
        mapView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }

        // centerPin
        centerPin.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.width.equalTo(30)
            make.height.equalTo(60)
        }
        centerPin.contentMode = .scaleAspectFit
        
        // searchBar
        view.addSubview(searchBar) // searchBar 뷰에 추가
        searchBar.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
            make.left.equalToSuperview().offset(10)
            make.right.equalToSuperview().offset(-10)
        }
    }

    private func setupSearchBar() {
        searchBar.delegate = self
        view.addSubview(searchBar)
    }

    private func centerMapOnUserLocation() {
        if let location = locationManager.location?.coordinate {
            let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 500, longitudinalMeters: 500)
            mapView.setRegion(region, animated: true)
        }
    }

    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        let center = mapView.centerCoordinate
        getAddressFromCoordinates(center)
    }

    private func getAddressFromCoordinates(_ coordinates: CLLocationCoordinate2D) {
        let location = CLLocation(latitude: coordinates.latitude, longitude: coordinates.longitude)
        geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
            if let error = error {
                print("Error getting address: \(error)")
                return
            }
            if let placemark = placemarks?.first {
                // 주소 정보
                let street = placemark.thoroughfare ?? ""
                let subStreet = placemark.subThoroughfare ?? ""
                let city = placemark.locality ?? ""
                let state = placemark.administrativeArea ?? ""
                let postalCode = placemark.postalCode ?? ""
                let country = placemark.country ?? ""
                
                let addressString = "\(country), \(city), \(street) \(subStreet), \(state) \(postalCode)"
                print(addressString) // 조합된 주소 정보 출력
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let region = MKCoordinateRegion(center: center, latitudinalMeters: 500, longitudinalMeters: 500)
        mapView.setRegion(region, animated: true)
    }

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        searchBar.resignFirstResponder()
        
        let request = MKLocalSearch.Request()
        request.naturalLanguageQuery = searchBar.text
        
        let search = MKLocalSearch(request: request)
        search.start { (response, error) in
            guard let response = response else {
                print("Error: \(error?.localizedDescription ?? "Unknown error").")
                return
            }
            
            let mapItem = response.mapItems[0]
            let placemark = mapItem.placemark
            let coordinates = placemark.coordinate
            let region = MKCoordinateRegion(center: coordinates, latitudinalMeters: 500, longitudinalMeters: 500)
            self.mapView.setRegion(region, animated: true)
        }
    }
}

 

위치허용

 

사용자 위치 표시 및 위치정보 print

 

마커핀 이동 시 위치 값 변경

 

 

'Dev > SWIFT' 카테고리의 다른 글

[Swift] FSCalendar 라이브러리  (0) 2024.03.06
[Swift] SPM(Swift Package Manager)으로 SnapKit 추가하기  (0) 2024.02.28
[Swift] MapKit 지도 나타내기  (0) 2024.02.26
[Swift] Enum 열거형  (0) 2024.02.23
[Swift] Live Activity?  (2) 2024.02.22