카카오맵 v2 iOS 질문

[FAQ] 지도/로컬 API 문의 전 꼭 읽어 주세요.
https://devtalk.kakao.com/t/faq-api/125610

한 화면에서 2개 이상의 지도를 띄울 수도 있나요?

@JerryKhw 가능은 하지만 권장하지 않습니다.

@vectordev

아래처럼 사용했는데 지도가 한개밖에 안나옵니다.
어떻게 해야 여러개를 띄울 수 있나요?

import SwiftUI
import KakaoMapsSDK

struct ContentView: View {
    @State var draw1: Bool = false
    @State var draw2: Bool = false
    var body: some View {
        VStack {
            KakaoMapView(draw: $draw1, viewName: "1").onAppear(perform: {
                        self.draw1 = true
                    }).onDisappear(perform: {
                        self.draw1 = false
                    }).frame(maxWidth: .infinity, maxHeight: .infinity)
                KakaoMapView(draw: $draw2, viewName: "2").onAppear(perform: {
                        self.draw2 = true
                    }).onDisappear(perform: {
                        self.draw2 = false
                    }).frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

struct KakaoMapView: UIViewRepresentable {
    @Binding var draw: Bool
    var viewName: String
    
    /// UIView를 상속한 KMViewContainer를 생성한다.
    /// 뷰 생성과 함께 KMControllerDelegate를 구현한 Coordinator를 생성하고, 엔진을 생성 및 초기화한다.
    func makeUIView(context: Self.Context) -> KMViewContainer {
        let view: KMViewContainer = KMViewContainer()
        view.sizeToFit()
        context.coordinator.createController(view)
        context.coordinator.controller?.initEngine()
        
        return view
    }

    
    /// Updates the presented `UIView` (and coordinator) to the latest
    /// configuration.
    /// draw가 true로 설정되면 엔진을 시작하고 렌더링을 시작한다.
    /// draw가 false로 설정되면 렌더링을 멈추고 엔진을 stop한다.
    func updateUIView(_ uiView: KMViewContainer, context: Self.Context) {
        if draw {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                context.coordinator.controller?.startEngine()
                context.coordinator.controller?.startRendering()
            }
        }
        else {
            context.coordinator.controller?.stopRendering()
            context.coordinator.controller?.stopEngine()
        }
    }
    
    /// Coordinator 생성
    func makeCoordinator() -> KakaoMapCoordinator {
        return KakaoMapCoordinator(viewName: viewName)
    }

    /// Cleans up the presented `UIView` (and coordinator) in
    /// anticipation of their removal.
    static func dismantleUIView(_ uiView: KMViewContainer, coordinator: KakaoMapCoordinator) {
        
    }
    
    /// Coordinator 구현. KMControllerDelegate를 adopt한다.
    class KakaoMapCoordinator: NSObject, MapControllerDelegate {
        init(viewName: String) {
            first = true
            self.viewName = viewName
            super.init()
        }
        
         // KMController 객체 생성 및 event delegate 지정
        func createController(_ view: KMViewContainer) {
            controller = KMController(viewContainer: view)
            controller?.delegate = self
        }
        
         // KMControllerDelegate Protocol method구현
         
          /// 엔진 생성 및 초기화 이후, 렌더링 준비가 완료되면 아래 addViews를 호출한다.
          /// 원하는 뷰를 생성한다.
        func addViews() {
            let defaultPosition: MapPoint = MapPoint(longitude: 127.108678, latitude: 37.402001)
            let mapviewInfo: MapviewInfo = MapviewInfo(viewName: viewName, viewInfoName: "map", defaultPosition: defaultPosition)
            
            if controller?.addView(mapviewInfo) == Result.OK {
                let _ = controller?.getView(viewName) as! KakaoMap
            }
        }
        
        /// KMViewContainer 리사이징 될 때 호출.
        func containerDidResized(_ size: CGSize) {
            let mapView: KakaoMap? = controller?.getView(viewName) as? KakaoMap
            mapView?.viewRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
            if first {
                let cameraUpdate: CameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 127.108678, latitude: 37.402001), zoomLevel: 10, mapView: mapView!)
                mapView?.moveCamera(cameraUpdate)
                first = false
            }
        }
        
        var controller: KMController?
        var first: Bool
        var viewName: String
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@JerryKhw 스샷과 같이 하나의 뷰 안에 지도를 복수개 띄워야 하는 경우에는 MapControllerDelegate.addViews 에서 addView를 여러 개 하는 방식으로 사용하시면 됩니다.
KMViewContainer를 두 개 이상 사용하는 경우는 KMController도 각각 개별적으로 생성하여 KMViewContainer에 연결해야 합니다.

@vectordev
한개의 KakaoMapView 에서 KMViewContainer, KMController 를 여러개 생성해서 사용하라는 말씀이신건가요?

그것도 가능한 방법일 수는 있습니다. 샘플의 KakaoMapView는 UIView 로 제공된 KMViewContainer를 SwiftUI 에서 띄우기 위해 구성된 것입니다. 중요한 점은 KMViewContainer와 KMController는 쌍으로 생성해서 사용해야 한다는 것입니다.
(KMViewContainer, KMController) 쌍을 여러 개 만들어서 사용하시거나, 하나의 KMViewContainer 안에서 KMController.addView 여러 개 해서 지도 여러 개를 띄울 수 있습니다.

@vectordev
쌍으로 여러개 만들어서 사용하면 된다고 하셨는데 KMController 의 initEngine() 사용 시 기존 사용중인 엔진을 비활성화 시키는 것 같은데 어떻게 사용해야되는건가요?

시뮬레이터에서 동작하는 OpenGL 모드의 경우 GL 오동작을 막기 위해 엔진 두개가 동시에 동작하지 못하도록 하고 있습니다. 디바이스에서는 Metal로 동작하고 Metal 모드에서는 이러한 제약이 없습니다.

1개의 좋아요

@vectordev
아 지금까지 시물레이터에서 실행해서 한개만 나오고 있던거네요.
답변 감사합니다!

@vectordev
안녕하세요. 혹시 한 화면에 두개 이상의 지도를 표시하는 것을 권장하지 않는 이유가 있을까요?
또 권장하지 않는다는 것은 iOS에만 해당하는건가요?

@jjj1211 v2 SDK는 기본적으로 하나의 엔진이 동작하는 상황에 맞춰 설계되었습니다. 동시에 복수개의 엔진이 실행(렌더링) 되는 상황에서 동작은 될 수 있으나 그러한 환경에서 모든 상황에 문제 없이 동작하는 것을 보장하지 않습니다.
해당 사항은 Android/iOS 모두에 해당됩니다.

1개의 좋아요