ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ios - Swift] MapView 사용하기 (MKMapView 2 / 2)
    ios 2020. 12. 23. 11:01

     

    이번 글에서는 지난 글에서 얘기한 것과 같이 지역 내 검색 및 좌표에 대한 정보를 추출하는 방법을 알아보도록 하겠습니다.

     

    위 gif를 살펴보면 맵 뷰의 현재 위치, 중앙 위치의 주소, 주변 가게들이 나오는 것을 확인할 수 있습니다.

     

    해당 기능을 사용할 수 있도록 하나씩 작성해 보도록 하겠습니다.

     

     

    1. 내 위치 찾기

    @IBAction func changeValue(_ sender: UISegmentedControl) {
        // "현재 위치" 선택 - 현재 위치 표시
        if sender.selectedSegmentIndex == 0 {
            self.mainTitle.text = ""
            self.subTitle.text = ""
            // 사용자의 현재 위치
            locationManager.startUpdatingLocation()
        } else if sender.selectedSegmentIndex == 1 {
            setAnnotation(latitudeValue: 37.5207945, longitudeValue: 127.0204729, delta: 0.01, title: "가로수길 서비스 센터", subtitle: "서울 강남구 가로수길 43")
    
            self.mainTitle.text = "보고 계신 위치"
            self.subTitle.text = "가로수길 서비스 센터"
        }
    }

    SegmentedControl Index 가 0 일 경우 현 위치 업데이트를 실행하도록 합니다.

     

     

    extension ViewController: CLLocationManagerDelegate {
    
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            let pLocation = locations.last
            moveLocation(latitudeValue: (pLocation?.coordinate.latitude)!, longtudeValue: (pLocation?.coordinate.longitude)!, delta: 0.01)
            
            CLGeocoder().reverseGeocodeLocation(pLocation!, completionHandler: { (placemarks, error) -> Void in
                if let pm: CLPlacemark = placemarks?.first {
                    let address: String = "\(pm.locality ?? "") \(pm.name ?? "")"
      
                    self.mainTitle.text = "내 위치"
                    self.subTitle.text = address
                }
            })
            
            locationManager.stopUpdatingLocation()
        }
    }

    CLLocationManagerDelegate에서 위치 정보 업데이트가 완료되면 위도, 경도에 해당하는 위치의 정보를 추출하도록 합니다.

     

     

    2. 맵 뷰 중앙 위치의 정보

     

    위의 gif에서는 화면이 이동할 때마다 중앙의 위치를 가져오는 것을 확인할 수 있습니다.

     

    내 위치와 마찬가지로 동일한 방법으로 찾으면 되는데 이때 주의할 점은 reverseGeocodeLocation를 짧은 시간 안에 너무 자주 호출을 하면 안 된다는 점입니다.

     

    짧은 시간에 많은 호출을 할 경우 결과를 받아올 수 없게 됩니다.

     

    mapViewDidChangeVisibleRegion을 이용하여 뷰의 가시영역이 변경될 때마다 맵 뷰의 중앙 위치를 표시할 것인데 마지막 변경에만 작업할 수 있게 하겠습니다.

     

     

    var runTimeInterval: TimeInterval? // 마지막 작업을 설정할 시간
    let mTimer: Selector = #selector(Tick_TimeConsole) // 위치 확인 타이머
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: mTimer, userInfo: nil, repeats: true)
    }

     

    viewDidLoad에 타이머를 추가해 주도록 합니다. 앞으로 맵 뷰의 중앙 위치 정보는 타이머에서 변경하도록 할 것입니다.

     

     

    extension ViewController: MKMapViewDelegate {
        func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
            runTimeInterval = Date().timeIntervalSinceReferenceDate
        }
    }

    뷰의 가시영역이 변경이 언제가 마지막인지 확인할 수 있도록 델리게이트에서 시간을 체크하도록 합니다. 

     

     

    @objc func Tick_TimeConsole() {
            
        guard let timeInterval = runTimeInterval else { return }
            
        let interval = Date().timeIntervalSinceReferenceDate - timeInterval
            
        if interval < 0.25 { return }
            
        let coordinate = mapkit.centerCoordinate
            
        let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
    
        // 지정된 위치의 지오 코드 요청
        CLGeocoder().reverseGeocodeLocation(location) { (placemarks, error) in
            if let pm: CLPlacemark = placemarks?.first {
                let address: String = "\(pm.country ?? "") \(pm.administrativeArea ?? "") \(pm.locality ?? "") \(pm.subLocality ?? "") \(pm.name ?? "")"
                self.centerMainTitle.text = "화면 중앙 위치"
                self.centerSubTitle.text = address
            } else {
                self.centerMainTitle.text = ""
                self.centerSubTitle.text = ""
            }
        }
        runTimeInterval = nil
    }

    확인된 마지막 변경 시간에서 0.25초가 이상 경과해야 위치 정보를 업데이트할 수 있도록 했습니다.

     

     

     

     

     

     

    var annotations:[MKAnnotation] = []
    let categoryArray = ["카페", "편의점", "은행", "주유소", "선별 진료소"]
    
    
    extension ViewController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return categoryArray.count
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCell", for: indexPath) as! CategoryCell
            cell.categoryLabel.text = categoryArray[indexPath.row]
            return cell
        }
        
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
            setSearchAnnotation(query: self.categoryArray[indexPath.row])
        }
        
        func setSearchAnnotation(query:String) {
    
            annotations.removeAll()
            mapkit.removeAnnotations(mapkit.annotations)
    
            let request = MKLocalSearch.Request()
            request.naturalLanguageQuery = "\(query)"
            request.region = mapkit.region
    
            let search = MKLocalSearch(request: request)
    
            search.start { (response, error) in
                guard let responseMap = response?.mapItems else { return }
    
                for item in responseMap {
                    let annotation = MKPointAnnotation()
                    annotation.coordinate = item.placemark.coordinate
                    annotation.title = item.name
                    annotation.subtitle = item.phoneNumber
    
                    self.annotations.append(annotation)
                }
                self.mapkit.addAnnotations(self.annotations)
            }
        }
    }

     

    댓글

Designed by Tistory.