Naver Map

김정현·2023년 9월 28일
0

Project1: Lost Item

목록 보기
3/9
post-thumbnail

맨 처음 어플을 제작하는 과정에선 카카오맵을 사용했었다. 이유는 카카오 로그인 기능을 사용하면서 카카오 sdk를 설치했는데, 로그인 기능과 맵 기능을 같이 설치할 수 있을거 같아서다.

그런데 카카오맵은 우선 objective-c 언어를 기본으로 구현되어있고, 그래도 변환이 가능하긴 하지만 맵 마커 기능이 제대로 구현이 안되는 것 같았다. LostItem에서는 마커를 자유롭게 사용할 수 있는 것이 핵심 기능이기 때문에 Naver Map으로 변경했다.

NMFNaverMapView vs NMFMapView

맵을 구현하는데 두 가지 종류가 있다. 우선은 NMFNaverMapView가 더 상위호환 버전이라고 생각하면 쉽다. 모든 기능과 최신업데이트를 사용한다. 반면 NMFMapView는 좀 더 간소화 된 인터페이스를 제공하며 맵 제공이외에 별다른 기능이 필요없다면 채택할만 하다.
나는 마커 기능, 현재 위치 기능이 필요하기 때문에 NMFNaverMapView를 채택했다.

맵 구현 자체는 공식 문서를 따라한다면 큰 어려움 없이 구현이 가능하다. 그러나 본 프로젝트에서 문제는 마커 기능 구현이었는데,

  1. 사용자가 마커 위치를 지정해서 분실물 위치를 등록한다.
  1. 해당 위치를 FireStore를 사용해서 좌표화 및 게시글 형태로 저장한다.
  1. 해당 좌표의 마커를 코드로 구현한다.
  1. 해당 마커를 클릭할시 (2)에서 저장했던 게시글 정보를 출력한다.

와 같이 단순하지않은 작업이다.

내가 이 과정을 구현한 방식은 게시글을 작성한 후 (게시글 작성 관련된 것은 후에 따로 작성할 예정) 맵 중앙에 사용자가 임시 마커를 확인할 수 있으며, 맵을 임의로 이동시켜 마커를 원하는 위치에 고정시켜 게시글 작성 및 좌표를 저장한다.

FireStore 이용

 func saveCenterCoordinates() {
        if let subView = subView { // subView 변수가 올바른지 확인
            let centerX = subView.frame.width / 2
            let centerY = subView.frame.height / 2
            
            // 중앙 좌표를 화면 좌표부터 지도 좌표로 변환
            let centerLatLng = subView.mapView.projection.latlng(from: CGPoint(x: centerX, y: centerY))
            
            // Firestore 데이터베이스에 접근
            let db = Firestore.firestore()
            
            // "게시글" 컬렉션에 좌표를 저장
            let data: [String: Any] = [
                "latitude": centerLatLng.lat,
                "longitude": centerLatLng.lng
                // 다른 필요한 데이터도 함께 저장
            ]
            
            let collectionRef = db.collection("게시글")
            
            let documentRef = collectionRef.document(self.titleLabel)
            documentRef.getDocument { (document, error) in
                if let document = document, document.exists {
                    // 문서가 존재하면 업데이트 작업 수행
                    documentRef.updateData(data) { err in
                        if let err = err {
                            print("Error updating document: \(err)")
                        } else {
                            print("Document updated")
                        }
                    }
                }
            }
        }
    }

이렇게 좌표를 저장한 후, 이 좌표를 마커로 변환 해주는 것을 진행한다.

// Firestore에서 "게시글" 컬렉션의 문서를 가져와서 좌표 데이터 필드를 네이버지도의 마커로 표시
   func fetchMarkersFromFirestore() {
       let db = Firestore.firestore()
       let collectionRef = db.collection("게시글")
       
       collectionRef.getDocuments { (snapshot, error) in
           if let error = error {
               print("Error getting documents: \(error.localizedDescription)")
               return
           }
           
           guard let documents = snapshot?.documents else {
               print("No documents found.")
               return
           }
           
           // 각 문서에서 좌표 데이터 필드를 추출하고 네이버지도의 마커로 표시
           for document in documents {
               let data = document.data()
               
               if let latitude = data["latitude"] as? Double,
                  let longitude = data["longitude"] as? Double {
                   // 좌표를 이용하여 네이버지도의 마커를 생성하고 추가
                   let marker = NMFMarker()
                   marker.position = NMGLatLng(lat: latitude, lng: longitude)
                   marker.mapView = self.subView.mapView
                   
                   //마커 이미지 및 크기 지정
                   marker.iconImage = NMFOverlayImage(name: "free-icon-lost-items-3372390-3.png")
                   marker.width = 30
                   marker.height = 30
                   
                   let storyboard = UIStoryboard(name: "Register", bundle: nil)
                   guard let PostViewControllerVC = storyboard.instantiateViewController(withIdentifier: "PostViewController") as? PostViewController else { return }
                   
                   // 마커를 탭할시 정보창 보여줌
                   let handler = { [weak self] (overlay: NMFOverlay) -> Bool in
                       if let marker = overlay as? NMFMarker {
                           // 현재 마커에 정보 창이 열려있지 않을 경우 엶
                           PostViewControllerVC.latitude = marker.position.lat
                           PostViewControllerVC.longitude = marker.position.lng
                           self?.present(PostViewControllerVC, animated: true)
                           PostViewControllerVC.deleteBtn.isHidden = true
                           PostViewControllerVC.ChatButton.isHidden = false
                           let db = Firestore.firestore()
                           db.collection("게시글")
                               .whereField("latitude", isEqualTo: latitude)
                               .whereField("longitude", isEqualTo: longitude)
                               .getDocuments { (querySnapshot, error) in
                                   if let error = error {
                                       print("Error fetching documents: \(error)")
                                       return
                                   }
                                   
                                   if let document = querySnapshot?.documents.first {
                                       // 문서가 존재하면 필드 값을 가져와 화면에 표시
                                       let documentID = document.documentID
                                       PostViewControllerVC.titleLabel.text = documentID
                                       if let chatuser = document["유저"] as? String {
                                           PostViewControllerVC.chatUser = chatuser
                                       }
                                   }
                               }
                       }
                       return true
                   };
                   
                   marker.touchHandler = handler
                   
               }
           }
       }
   }

마커의 이미지 및 크기를 지정해주고 FireStore에 저장했던 좌표를 기준으로 마커를 지정해준다.

그리고 또 중요했던 점은 touch handler를 사용하여 마커를 클릭했을때 액션을 만들 수 있다.
해당 앱에서는 마커를 클릭했을시 분실물의 정보들을 가진 Post를 present형식으로 나오게끔 하였다.

UI 구성전 간단한 예시 사진)

0개의 댓글