카카오맵 실시간 위치 마커에 프로필사진 띄우기

Juhee Kim·2025년 2월 26일
0

이슈

👉 사용자의 실시간 위치를 지도에 표시할 때, 심볼로 원형 위에 프로필이미지를 겹친 를 이미지 대신 띄우는 것이 목표.

원인

👉 카카오맵에서 지원하는 마커(Poi) 형식은 UIImage로 한정되어 있어, 커스텀 마커를 띄울 수 없었음

해결

👉 심볼이 될 뷰를 만들고, Extention을 통해 뷰를 UIImage로 변환시키는 함수 작성

최종 코드

ProfileImageView:

import SwiftUI

// 프로필 이미지를 위한 SwiftUI View
struct ProfileImageView: View {
    let image: Image
    
    var body: some View {
        ZStack {
            Image("icon-location-anchor")
                .frame(width: LayoutAdapter.shared.scale(value: 11), height: LayoutAdapter.shared.scale(value: 11))
                .padding(.top, 55)
            Image("icon-location-pin")
                .frame(width: LayoutAdapter.shared.scale(value: 45), height: LayoutAdapter.shared.scale(value: 56))
            
            image
                .resizable()
                .scaledToFill()
                .frame(width: LayoutAdapter.shared.scale(value: 37), height: LayoutAdapter.shared.scale(value: 37))
                .clipShape(Circle())
                .frame(width: LayoutAdapter.shared.scale(value: 10), height: LayoutAdapter.shared.scale(value: 10))
                .padding(.bottom, 10)
        }
    }
}

Extensions:

// MARK: View to UIImage - 실시간 위치 조회시 프로필사진 마킹용
extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self.edgesIgnoringSafeArea(.all))
        let view = controller.view
        
        let targetSize = controller.view.intrinsicContentSize
        
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

// MARK: 이미지 크기 조절
extension UIImage {
    func resizedForProfile(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

MapPinView:

// Poi 표시 스타일 생성
        func createPoiStyle() {
            guard let view = controller?.getView(mapViewName) as? KakaoMap else {
                print("view is nil in createPoiStyle")
                return
            }
            let manager = view.getLabelManager()
            
            // 내 마커용 스타일 생성: SwiftUI View를 UIImage로 변환
            let myMarker = ProfileImageView(image: Image(myLocation?.member?.profileImage ?? "icon-profile-default"))
            let mySymbolImage = myMarker.snapshot().resizedForProfile(to: CGSize(width: LayoutAdapter.shared.scale(value: 30), height: LayoutAdapter.shared.scale(value: 40.667)))
            let myIconStyle = PoiIconStyle(symbol: mySymbolImage, anchorPoint: CGPoint(x: 0.5, y: 1))
            let myPoiStyle = PoiStyle(styleID: "myPoiStyle", styles: [
                PerLevelPoiStyle(iconStyle: myIconStyle, level: 12)
            ])
            manager.addPoiStyle(myPoiStyle)
            
            // 친구들 각각의 마커 스타일 생성
            for (index, friend) in friendsLocation.enumerated() {
                let profileImageName = friend.member?.profileImage ?? "icon-profile-default"
                let friendMarker = ProfileImageView(image: Image(profileImageName))
                let friendSymbolImage = friendMarker.snapshot().resizedForProfile(to: CGSize(width: LayoutAdapter.shared.scale(value: 30), height: LayoutAdapter.shared.scale(value: 40.667)))
                let friendIconStyle = PoiIconStyle(symbol: friendSymbolImage, anchorPoint: CGPoint(x: 0.5, y: 1))
                
                // 각 친구별로 고유한 styleID 생성
                let styleID = "friendPoiStyle_\(index)"
                let friendPoiStyle = PoiStyle(styleID: styleID, styles: [
                    PerLevelPoiStyle(iconStyle: friendIconStyle, level: 12)
                ])
                manager.addPoiStyle(friendPoiStyle)
            }
        }
        
        func createPois() {
            guard let view = controller?.getView(mapViewName) as? KakaoMap else {
                print("view is nil in createPois")
                return
            }
            let manager = view.getLabelManager()
            let layer = manager.getLabelLayer(layerID: "PoiLayer")
            
            // 내 위치 POI 생성
            let myPoiOption = PoiOptions(styleID: "myPoiStyle")
            myPoiOption.rank = 0
            
            if let myLocation {
                let myPoi = layer?.addPoi(
                    option: myPoiOption,
                    at: MapPoint(longitude: myLocation.x, latitude: myLocation.y)
                )
                myPoi?.show()
            }
            
            // 친구들 위치 POI 생성 - 각각 다른 스타일 적용
            for (index, friend) in friendsLocation.enumerated() {
                let friendPoiOption = PoiOptions(styleID: "friendPoiStyle_\(index)")
                friendPoiOption.rank = 1
                
                let friendPoi = layer?.addPoi(
                    option: friendPoiOption,
                    at: MapPoint(longitude: friend.x, latitude: friend.y)
                )
                friendPoi?.show()
            }
        }

참고
https://stickode.tistory.com/448

profile
개: 개롭지만 발: 발전하는중

0개의 댓글

관련 채용 정보