8
8
import NMapsMap
9
9
import UIKit
10
10
11
+ /// 네이버 지도(NMapsMap)에서 사용할 커스텀 마커 클래스
12
+ /// 말풍선 형태의 UI를 제공하며, 좌우 텍스트를 포함할 수 있음
11
13
public final class ESMarker {
12
14
// MARK: - Properties
13
15
16
+ /// 네이버 지도(Naver Map)에 표시될 마커 객체
14
17
public private( set) var marker : NMFMarker
18
+ /// 마커와 연결된 데이터 (예: 식당 정보, 위치 정보 등)
15
19
private var data : Any
20
+ /// 말풍선의 왼쪽에 표시될 텍스트
16
21
private var leftText : String
22
+ /// 말풍선의 오른쪽에 표시될 텍스트
17
23
private var rightText : String
18
24
19
- // MARK: - Layout Constants
25
+ // MARK: - Layout Constants (말풍선 레이아웃 관련 상수)
20
26
21
27
private enum Layout {
28
+ /// 말풍선 내부의 좌우 여백 (padding)
22
29
static let horizontalPadding : CGFloat = 12
30
+ /// 말풍선 내부의 상하 여백 (padding)
23
31
static let verticalPadding : CGFloat = 12
32
+ /// 왼쪽과 오른쪽 말풍선 사이의 간격
24
33
static let spacing : CGFloat = 10
34
+ /// 말풍선의 모서리를 둥글게 만드는 반경 (corner radius)
25
35
static let cornerRadius : CGFloat = 15
26
- static let tailHeight : CGFloat = 8
27
- static let leftBubblePadding : CGFloat = 20
36
+ /// 왼쪽 말풍선이 시작되는 위치의 좌측 여백
37
+ static let leftBubblePadding : CGFloat = 4
28
38
}
29
39
30
- // MARK: - Initializer
40
+ // MARK: - Initializer (초기화 메서드)
31
41
42
+ /// ESMarker 인스턴스를 초기화하는 생성자
43
+ /// - Parameters:
44
+ /// - position: 마커가 지도에 표시될 위치 (위도, 경도)
45
+ /// - data: 마커에 연결할 데이터 (예: POI 정보)
46
+ /// - leftText: 왼쪽 말풍선에 표시할 텍스트
47
+ /// - rightText: 오른쪽 말풍선에 표시할 텍스트
32
48
public init ( position: NMGLatLng , data: Any , leftText: String , rightText: String ) {
33
49
marker = NMFMarker ( )
34
50
marker. position = position
@@ -38,35 +54,45 @@ public final class ESMarker {
38
54
updateImage ( )
39
55
}
40
56
41
- // MARK: - Methods
57
+ // MARK: - Methods (기능 구현)
42
58
59
+ /// 마커의 위치를 변경하는 함수
60
+ /// - Parameter newPosition: 새롭게 설정할 위치 (위도, 경도)
43
61
public func updatePosition( newPosition: NMGLatLng ) {
44
62
marker. position = newPosition
45
63
}
46
64
65
+ /// 왼쪽 말풍선의 텍스트를 업데이트하는 함수
66
+ /// - Parameter newLeftText: 변경할 새로운 왼쪽 텍스트
47
67
public func updateLeftText( newLeftText: String ) {
48
68
leftText = newLeftText
49
69
updateImage ( )
50
70
}
51
71
72
+ /// 오른쪽 말풍선의 텍스트를 업데이트하는 함수
73
+ /// - Parameter newRightText: 변경할 새로운 오른쪽 텍스트
52
74
public func updateRightText( newRightText: String ) {
53
75
rightText = newRightText
54
76
updateImage ( )
55
77
}
56
78
79
+ /// 마커의 이미지를 업데이트하여 현재 텍스트가 반영되도록 설정
57
80
private func updateImage( ) {
58
81
let image = ESMarker . createESMarkerImage ( leftText: leftText, rightText: rightText)
59
82
marker. iconImage = NMFOverlayImage ( image: image)
60
83
marker. width = image. size. width
61
84
marker. height = image. size. height
62
- marker. anchor = CGPoint ( x: 0.5 , y: 1.0 ) // 🔼 꼬리가 마커 위치에 정확히 오도록 앵커 조정
85
+ marker. anchor = CGPoint ( x: 0.5 , y: 1.0 ) // 마커의 하단 중심을 지도 좌표에 맞춰 배치
63
86
}
64
87
88
+ /// 좌우 텍스트를 포함하는 말풍선 형태의 이미지를 생성
89
+ /// - Parameters:
90
+ /// - leftText: 왼쪽 말풍선의 텍스트
91
+ /// - rightText: 오른쪽 말풍선의 텍스트
92
+ /// - Returns: 생성된 UIImage 객체
65
93
private static func createESMarkerImage( leftText: String , rightText: String ) -> UIImage {
66
- // Font
67
94
let font = EATSSUDesignFontFamily . Pretendard. regular. font ( size: 12 )
68
95
69
- // Text Attributes
70
96
let leftAttributes : [ NSAttributedString . Key : Any ] = [
71
97
. font: font,
72
98
. foregroundColor: UIColor . systemMint,
@@ -76,74 +102,77 @@ public final class ESMarker {
76
102
. foregroundColor: UIColor . black,
77
103
]
78
104
79
- // Text Size Calculation
105
+ // 텍스트 크기 계산
80
106
let leftTextSize = ( leftText as NSString ) . size ( withAttributes: leftAttributes)
81
107
let rightTextSize = ( rightText as NSString ) . size ( withAttributes: rightAttributes)
82
108
83
- // Bubble Dimensions
109
+ // 말풍선 크기 계산
84
110
let leftBubbleWidth = leftTextSize. width + Layout. horizontalPadding * 2
85
111
let leftBubbleHeight = leftTextSize. height + Layout. verticalPadding * 2
86
112
let rightBubbleWidth = rightTextSize. width + Layout. horizontalPadding * 2
113
+ let rightBubbleHeight = rightTextSize. height + Layout. verticalPadding * 2
87
114
88
- let totalWidth = Layout . leftBubblePadding + leftBubbleWidth + Layout. spacing + rightBubbleWidth
89
- let bubbleHeight = max ( leftBubbleHeight, rightTextSize. height + Layout. verticalPadding * 2 )
90
- let totalHeight = bubbleHeight + Layout. tailHeight
115
+ let totalWidth = Layout . leftBubblePadding
116
+ + leftBubbleWidth
117
+ + Layout. spacing
118
+ + rightBubbleWidth
91
119
92
- // Image Rendering
120
+ let bubbleHeight = max ( leftBubbleHeight, rightBubbleHeight)
121
+
122
+ // 배경 높이를 말풍선보다 5 크게 설정
123
+ let totalHeight = bubbleHeight + 5
124
+
125
+ // 이미지 렌더러 설정
93
126
let renderer = UIGraphicsImageRenderer ( size: CGSize ( width: totalWidth, height: totalHeight) )
94
127
return renderer. image { _ in
95
- // 1. Background & Tail
96
- let backgroundRect = CGRect ( x: 0 , y: 0 , width: totalWidth, height: bubbleHeight)
97
- let backgroundPath = UIBezierPath ( roundedRect: backgroundRect, cornerRadius: Layout . cornerRadius)
128
+ // 배경 (흰색 사각형)
129
+ let backgroundRect = CGRect ( x: 0 , y: 0 , width: totalWidth, height: totalHeight)
130
+ let backgroundPath = UIBezierPath (
131
+ roundedRect: backgroundRect,
132
+ cornerRadius: Layout . cornerRadius
133
+ )
98
134
UIColor . white. setFill ( )
99
135
backgroundPath. fill ( )
100
136
101
- // Tail Drawing (Centered)
102
- let tailPath = UIBezierPath ( )
103
- let tailCenterX = totalWidth / 2
104
- tailPath. move ( to: CGPoint ( x: tailCenterX - 6 , y: bubbleHeight) )
105
- tailPath. addLine ( to: CGPoint ( x: tailCenterX, y: totalHeight) )
106
- tailPath. addLine ( to: CGPoint ( x: tailCenterX + 6 , y: bubbleHeight) )
107
- tailPath. close ( )
108
- UIColor . white. setFill ( )
109
- tailPath. fill ( )
137
+ // 말풍선이 배경의 중앙에 오도록 Y축 위치 조정
138
+ let bubbleTop = ( totalHeight - bubbleHeight) / 2
110
139
111
- // 2. Left Bubble
140
+ // 왼쪽 말풍선 (연한 민트색 배경)
112
141
let leftBubbleRect = CGRect (
113
142
x: Layout . leftBubblePadding,
114
- y: 0 ,
143
+ y: bubbleTop ,
115
144
width: leftBubbleWidth,
116
145
height: bubbleHeight
117
146
)
118
147
let leftBubblePath = UIBezierPath ( roundedRect: leftBubbleRect, cornerRadius: Layout . cornerRadius)
119
148
UIColor . systemMint. withAlphaComponent ( 0.2 ) . setFill ( )
120
149
leftBubblePath. fill ( )
121
150
122
- // Left Text Position
151
+ // 왼쪽 텍스트 그리기
123
152
( leftText as NSString ) . draw (
124
153
at: CGPoint (
125
154
x: Layout . leftBubblePadding + Layout. horizontalPadding,
126
- y: ( bubbleHeight - leftTextSize. height) / 2
155
+ y: bubbleTop + ( bubbleHeight - leftTextSize. height) / 2
127
156
) ,
128
157
withAttributes: leftAttributes
129
158
)
130
159
131
- // 3. Right Bubble
160
+ // 오른쪽 말풍선 (투명한 배경)
132
161
let rightBubbleRect = CGRect (
133
162
x: Layout . leftBubblePadding + leftBubbleWidth + Layout. spacing,
134
- y: 0 ,
163
+ y: bubbleTop ,
135
164
width: rightBubbleWidth,
136
165
height: bubbleHeight
137
166
)
138
167
let rightBubblePath = UIBezierPath ( roundedRect: rightBubbleRect, cornerRadius: Layout . cornerRadius)
139
168
UIColor . clear. setFill ( )
140
169
rightBubblePath. fill ( )
141
170
142
- // Right Text Position
171
+ // 오른쪽 텍스트 그리기
143
172
( rightText as NSString ) . draw (
144
173
at: CGPoint (
145
174
x: Layout . leftBubblePadding + leftBubbleWidth + Layout. spacing + Layout. horizontalPadding,
146
- y: ( bubbleHeight - rightTextSize. height) / 2
175
+ y: bubbleTop + ( bubbleHeight - rightTextSize. height) / 2
147
176
) ,
148
177
withAttributes: rightAttributes
149
178
)
0 commit comments