[iOS/Kakaomap/UIKit] 카카오맵 기본 설정 코드(No-Storyboard), Kakaomap viewRect

팔랑이·2024년 11월 18일
0

iOS/Swift

목록 보기
61/71
post-thumbnail

카카오맵 공식문서 그대로 복붙하면 맵이 생성이 안돼서 생성된 기본 코드를 공유/저장...
label이나 다른 레이어 처리할거면 addViewSucceeded 메서드 뒤에 넣으면 된다.

import CoreLocation
import UIKit
import KakaoMapsSDK
import SnapKit

class ViewController: UIViewController, MapControllerDelegate {
    
    var mapContainer: KMViewContainer?
    var mapController: KMController?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        mapContainer = KMViewContainer()
        view.addSubview(mapContainer!)
        mapContainer?.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        mapController = KMController(viewContainer: mapContainer!)
        mapController?.delegate = self
    }
    
    deinit {
        mapController?.pauseEngine()
        mapController?.resetEngine()
        
        print("deinit")
    }

    override func viewWillAppear(_ animated: Bool) {
        addObservers()
        
        if mapController?.isEnginePrepared == false {
            mapController?.prepareEngine()
        }
        
        if mapController?.isEngineActive == false {
            mapController?.activateEngine()
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        mapController?.pauseEngine()  //렌더링 중지.
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        removeObservers()
        mapController?.resetEngine()     //엔진 정지. 추가되었던 ViewBase들이 삭제된다.
    }
    
    func authenticationSucceeded() {
        mapController?.activateEngine()
    }
    
    // 인증 실패시 호출.
    func authenticationFailed(_ errorCode: Int, desc: String) {
        print("error code: \(errorCode)")
        print("desc: \(desc)")
        switch errorCode {
        case 400:
            showToast(self.view, message: "지도 종료(API인증 파라미터 오류)")
            break;
        case 401:
            showToast(self.view, message: "지도 종료(API인증 키 오류)")
            break;
        case 403:
            showToast(self.view, message: "지도 종료(API인증 권한 오류)")
            break;
        case 429:
            showToast(self.view, message: "지도 종료(API 사용쿼터 초과)")
            break;
        case 499:
            showToast(self.view, message: "지도 종료(네트워크 오류) 5초 후 재시도..")
            
            // 인증 실패 delegate 호출 이후 5초뒤에 재인증 시도..
            DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
                print("retry auth...")
                
                self.mapController?.prepareEngine()
            }
            break;
        default:
            break;
        }
    }
    
    func addViews() {
        //여기에서 그릴 View(KakaoMap, Roadview)들을 추가한다.
        let defaultPosition: MapPoint = MapPoint(longitude: 127.108678, latitude: 37.402001)
        //지도(KakaoMap)를 그리기 위한 viewInfo를 생성
        let mapviewInfo: MapviewInfo = MapviewInfo(viewName: "mapview", viewInfoName: "map", defaultPosition: defaultPosition, defaultLevel: 7)
        
        //KakaoMap 추가.
        mapController?.addView(mapviewInfo)
    }
    
    func addViewSucceeded(_ viewName: String, viewInfoName: String) {
        print("OK")
        let view = mapController?.getView("mapview") as! KakaoMap
        view.viewRect = mapContainer!.bounds
    }
    
    //addView 실패 이벤트 delegate. 실패에 대한 오류 처리를 진행한다.
    func addViewFailed(_ viewName: String, viewInfoName: String) {
        print("Failed")
    }
    
    //Container 뷰가 리사이즈 되었을때 호출된다. 변경된 크기에 맞게 ViewBase들의 크기를 조절할 필요가 있는 경우 여기에서 수행한다.
    func containerDidResized(_ size: CGSize) {
        let mapView: KakaoMap? = mapController?.getView("mapview") as? KakaoMap
        mapView?.viewRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)   //지도뷰의 크기를 리사이즈된 크기로 지정한다.
    }
    
    func addObservers(){
        NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
    }
    
    func removeObservers(){
        NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    }
    
    @objc func willResignActive(){
        mapController?.pauseEngine()  //뷰가 inactive 상태로 전환되는 경우 렌더링 중인 경우 렌더링을 중단.
    }
    
    @objc func didBecomeActive(){
        mapController?.activateEngine()//뷰가 active 상태가 되면 렌더링 시작. 엔진은 미리 시작된 상태여야 함.
    }
    
    func showToast(_ view: UIView, message: String, duration: TimeInterval = 2.0) {
        let toastLabel = UILabel(frame: CGRect(x: view.frame.size.width/2 - 150, y: view.frame.size.height-100, width: 300, height: 35))
        toastLabel.backgroundColor = UIColor.black
        toastLabel.textColor = UIColor.white
        toastLabel.textAlignment = NSTextAlignment.center;
        view.addSubview(toastLabel)
        toastLabel.text = message
        toastLabel.alpha = 1.0
        toastLabel.layer.cornerRadius = 10;
        toastLabel.clipsToBounds  =  true
        
        UIView.animate(withDuration: 0.4,
                       delay: duration - 0.4,
                       options: UIView.AnimationOptions.curveEaseOut,
                       animations: {
            toastLabel.alpha = 0.0
        },
                       completion: { (finished) in
            toastLabel.removeFromSuperview()
        })
    }
    

    
}

공식문서에서 addViewSucceeded 메서드 안에 view.viewRect 설정하는 부분이 없었는데, 저거 설정해주니까 기본 맵이 떴음

지피티한테 물어보니까,view.viewRect는 지도 뷰(KakaoMap)의 렌더링 영역을 설정하는 속성으로, 지도가 화면에서 어느 영역에 그려질지를 결정하는 사각형(Rect)을 정의한다고 한다.

이하는 지피티의 답변 복붙한 내용


viewRect의 역할

viewRectKakaoMap 객체가 화면에 표시될 좌표(x, y)크기(width, height)를 설정하는 속성으로, 지도의 렌더링 영역을 정밀하게 제어할 수 있어.

예를 들어:

  • viewRect = CGRect(x: 0, y: 0, width: 300, height: 400) → 지도는 화면의 왼쪽 위에서 시작하여 너비 300, 높이 400만큼만 표시.
  • viewRect = mapContainer!.boundsmapContainer의 크기와 위치를 기준으로 지도 영역을 설정.

왜 이 설정이 필요할까?

  1. 초기 설정 문제 해결:

    • addViews() 호출 이후, 맵 뷰의 렌더링 영역이 명시되지 않으면 지도가 화면에 표시되지 않을 수 있음.
    • viewRect를 설정해줘야 Kakao Maps SDK가 지도 타일을 올바르게 로드하고 화면에 그리도록 작동.
  2. 뷰의 크기 조정:

    • mapContainer의 크기와 위치가 변경되면, 지도 영역도 이에 맞게 업데이트해야 함.
    • 따라서 viewRectmapContainer.bounds로 설정하여 자동으로 크기와 위치를 동기화.
  3. 다중 뷰 지원:

    • 여러 개의 지도 뷰가 같은 컨테이너 안에 있을 경우, 각각의 뷰에 대해 다른 viewRect를 설정하여 원하는 영역에 표시할 수 있음.

왜 맵이 표시되었을까?

  • viewRect가 설정되지 않으면 지도는 기본적으로 (0, 0)에서 크기 (0, 0)으로 초기화되어, 화면에 아무것도 그려지지 않을 수 있어.
  • mapContainer.bounds를 기반으로 viewRect를 설정하면, mapContainer의 크기와 동일한 지도 렌더링 영역이 설정되어 맵이 제대로 보이게 된 거야.

관련 팁

  • 만약 지도 크기를 동적으로 변경해야 할 경우, containerDidResized에서 viewRect를 재설정하도록 처리:
func containerDidResized(_ size: CGSize) {
    let mapView = mapController?.getView("mapview") as? KakaoMap
    mapView?.viewRect = CGRect(origin: .zero, size: size)
}

이렇게 하면 화면 회전이나 크기 변경에도 지도 크기가 올바르게 조정돼.

profile
정체되지 않는 성장

1개의 댓글

comment-user-thumbnail
2024년 12월 12일

기가막히네요

답글 달기