Mapkit 를 배워보자 !!! - 1

godo·2022년 11월 5일
0

Mapkit

목록 보기
1/2

MapKit 이란 ?

맵이나 위성 이미지를 앱에 보여줄 수 있는 프레임워크입니다.
쓰는 방법을 위주로 블로깅 하겠습니다.

맵 보여주기

레이아웃

import MapKit

MapKit 을 쓰겠다고 선어해줍니다.

private var mapView = MKMapView()
...

view.addSubview(mapView)
mapView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
            mapView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            mapView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            mapView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            mapView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
        

그리고 이런식으로 레이아웃을 잡아줍니다.

범위 설정

private extension MKMapView {
    func centerToLocation(
        _ location: CLLocation,
        regionRadius: CLLocationDistance = 1000
    ) {
        let coordinateRegion = MKCoordinateRegion(
            center: location.coordinate,
            latitudinalMeters: regionRadius,
            longitudinalMeters: regionRadius
        )
        setRegion(coordinateRegion, animated: true)
    }
}

그리고 MKMapView 를 확장해주고 위와 같은 코드를 입력해줍니다.
해당 코드는 중심 좌표를 기준으로 어느 정도의 범위를 잡을 지를 정해주는 코드입니다.
여기서 CLLocationDistance 를 쓰는 데 이는 미터 단위를 나타내는 것입니다.
따라서 위의 메서드가 의마하는 것은 location 정보를 가져와 그것을 중심으로 위,경도 1000미터를 보여주는 맵을 보여주겠다는 것입니다.

그럼 저희 한번 한강대교를 배경으로 맵을 만들어 보죠?

let initialLocation = CLLocation(latitude: 37.517496, longitude: 126.959118)
        
mapView.centerToLocation(initialLocation)

자 이렇게 위치를 지정하고 메서드를 사용해서 보여줄 범위를 지정해주면?

Yes!!!

잘 되네요!!!

그런데 한 가지 문제점이 있습니다. 해당 사진을 드래그 하게 된다면? 범위를 한참 벗어납니다.

카메라 제한 주기

    private func cameraConstraining() {
        let initialLocation = CLLocation(latitude: 37.517496, longitude: 126.959118)
        let region = MKCoordinateRegion(
            center: initialLocation.coordinate,
            latitudinalMeters: 500,
            longitudinalMeters: 500
        )
        mapView.setCameraBoundary(
            MKMapView.CameraBoundary(coordinateRegion: region),
            animated: true
        )
        let zoomRange = MKMapView.CameraZoomRange(maxCenterCoordinateDistance: 20000)
        mapView.setCameraZoomRange(zoomRange, animated: true)
    }

이런식으로 범위를 정해주고 줌의 범위도 정해줄 수 있습니다.

근데 이제 좀 심심하지 않으신가요 ?

핀 찍기

자 맵은 이제 어떻게 다룰 줄 알꺼 같으면 이 맵에다가 먼가를 추가해 봅시다.

한번 이런식으로 된 것을 만들어 보도록 합시다 !!!

Artwork 파일 만들기


class Artwork: NSObject, MKAnnotation {
    
    let title: String?
    let locationName: String?
    let discipline: String?
    let coordinate: CLLocationCoordinate2D
    
    init(
        title: String?,
        locationName: String?,
        discipline: String?,
        coordinate: CLLocationCoordinate2D
    ) {
        self.title = title
        self.locationName = locationName
        self.discipline = discipline
        self.coordinate = coordinate
        
        super.init()
    }
    
    var subtitle: String? {
        return locationName
    }
    
}

이런 식으로 된 파일을 만들어 줍니다.
참고로 위의 Artwork 는 NSObject, MKAnnotation 이라는 프로토콜을 채택하고 있습니다.
그 중 MKAnnotation 프로토콜을 잠시 알아보도록 하겠습니다.

MKAnnotation

특정 맵의 위치에 관련된 컨텐츠를 띄워줄 수 있도록 하는 protocol 입니다.

해당 프로토콜은 위와 같이 정의 되어 있습니다.

이 프로토콜은 직접적으로 맵에 보여주는 것을 하지는 않지만, MapView 가 제공하는 딜리게이트가 제공하는 MKAnnotationView 라는 오브젝트에서 먼가를 보여주고 싶다고 할때 필요합니다.
만약 특정한 맵의 위치에 먼가를 보여주고 싶다면, annotation 오브젝트를 맵뷰에 추가해주어야 합니다.
만약 맵의 좌표에 주석을 보여줄 수 있다면, 맵 뷰는 자신의 딜리게이트에 주석과 관련된 적절한 뷰를 제공합니다.
mapView(_:viewFor:) 라는 딜리게이트의 메서드를 통해서 뷰를 제공합니다.
이 프로토콜을 채택한 객체는 coordinate 라는 프로퍼티가 필요하고 나머지는 optional 입니다.

즉, MKAnnotation 을 채택한 객체를 이용해야 맵에 무엇인가를 그려줄 수 있다 이런 이야기군요. (멋지다)

Annotation 추가

다시 돌아가서 Annotation 즉 주석을 추가해 봅시다 !

let nodeulArtwork = Artwork(
    title: "한강",
    locationName: "노들섬",
    discipline: "공원",
    coordinate: CLLocationCoordinate2D(latitude: 37.517892, longitude: 126.957671)
)

mapView.addAnnotation(nodeulArtwork)

이렇게 addAnnotation 메서드를 이용해서 Annotation 을 추가해주면???

핀이 찍히네요 ㅎㅎ

그러나 먼가 이걸론 부족합니다.
그림도 띄우고 싶고, 정보도 보여주고 싶고 해주고 싶은 게 많지 않으신가요?

Annotaion View 만들기

extension ViewController: MKMapViewDelegate {
    func mapView(
        _ mapView: MKMapView,
        viewFor annotation: MKAnnotation
    ) -> MKAnnotationView? {
        
        guard let annotation = annotation as? Artwork else { return nil }
        
        let identifier = "artwork"
        var view: MKMarkerAnnotationView
        
        if let dequeuedView = mapView
            .dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView {
            dequeuedView.annotation = annotation
            view = dequeuedView
        } else {
            view = MKMarkerAnnotationView(
                annotation: annotation,
                reuseIdentifier: identifier
            )
            view.canShowCallout = true
            view.calloutOffset = CGPoint(x: -10, y: 10)
            view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
        }
        
        return view
        
    }
}

...
mapView.delegate = self

이런식으로 코드를 짜줍니다.

그리고 실행시켜보면?

이렇게 뜨게 됩니다.

이제 코드를 설명해보도록 하겠습니다.
MKAnnotation 쪽을 제대로 읽어 보신분은 어? 먼가 익숙한데? 라는 게 보이실 껍니다.
중간에 딜리게이트 관련 부분이 있는 데 당시는 이해가 안 되셨을 지도 모르셨을 텐데 바로 이 부분이 위의 코드에 들어 들어 있습니다.

  • MKAnnotationView

바로 이게 뷰에 먼가를 보여주는 뷰입니다. 이 View 에 annotation 정보를 넣어서 보여주는 것입니다.

view = MKMarkerAnnotationView(
    annotation: annotation,
    reuseIdentifier: identifier
)

바로 이 부분

view.canShowCallout = true
view.calloutOffset = CGPoint(x: -10, y: 10)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

그리고 이 부분은 핀이 클릭 될떄 나오는 뷰와 관련된 부분입니다.

Reference

https://www.kodeco.com/7738344-mapkit-tutorial-getting-started#toc-anchor-002

profile
☀️☀️☀️

0개의 댓글