Skip to content

Commit 8208f0c

Browse files
committed
[#234] 단과대 정보가 담기는 LeftBubble과 BackgroundRectangle 간 Padding 추가
1 parent 0513acf commit 8208f0c

File tree

2 files changed

+65
-36
lines changed

2 files changed

+65
-36
lines changed

EATSSU/App/Sources/Presentation/Maps/ViewController/MapViewController.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ extension MapViewController {
5858
let marker = ESMarker(
5959
position: NMGLatLng(lat: latlng.lat, lng: latlng.lng),
6060
data: "Tapped Location",
61-
leftText: "Tapped",
62-
rightText: "Here"
61+
leftText: "Tapped Marker",
62+
rightText: "Here is the location"
6363
)
6464
marker.marker.mapView = mapView
6565
}

EATSSUDesign/EATSSUDesign/Sources/BrandDesignComponents/ESMarker/ESMarker.swift

+63-34
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,43 @@
88
import NMapsMap
99
import UIKit
1010

11+
/// 네이버 지도(NMapsMap)에서 사용할 커스텀 마커 클래스
12+
/// 말풍선 형태의 UI를 제공하며, 좌우 텍스트를 포함할 수 있음
1113
public final class ESMarker {
1214
// MARK: - Properties
1315

16+
/// 네이버 지도(Naver Map)에 표시될 마커 객체
1417
public private(set) var marker: NMFMarker
18+
/// 마커와 연결된 데이터 (예: 식당 정보, 위치 정보 등)
1519
private var data: Any
20+
/// 말풍선의 왼쪽에 표시될 텍스트
1621
private var leftText: String
22+
/// 말풍선의 오른쪽에 표시될 텍스트
1723
private var rightText: String
1824

19-
// MARK: - Layout Constants
25+
// MARK: - Layout Constants (말풍선 레이아웃 관련 상수)
2026

2127
private enum Layout {
28+
/// 말풍선 내부의 좌우 여백 (padding)
2229
static let horizontalPadding: CGFloat = 12
30+
/// 말풍선 내부의 상하 여백 (padding)
2331
static let verticalPadding: CGFloat = 12
32+
/// 왼쪽과 오른쪽 말풍선 사이의 간격
2433
static let spacing: CGFloat = 10
34+
/// 말풍선의 모서리를 둥글게 만드는 반경 (corner radius)
2535
static let cornerRadius: CGFloat = 15
26-
static let tailHeight: CGFloat = 8
27-
static let leftBubblePadding: CGFloat = 20
36+
/// 왼쪽 말풍선이 시작되는 위치의 좌측 여백
37+
static let leftBubblePadding: CGFloat = 4
2838
}
2939

30-
// MARK: - Initializer
40+
// MARK: - Initializer (초기화 메서드)
3141

42+
/// ESMarker 인스턴스를 초기화하는 생성자
43+
/// - Parameters:
44+
/// - position: 마커가 지도에 표시될 위치 (위도, 경도)
45+
/// - data: 마커에 연결할 데이터 (예: POI 정보)
46+
/// - leftText: 왼쪽 말풍선에 표시할 텍스트
47+
/// - rightText: 오른쪽 말풍선에 표시할 텍스트
3248
public init(position: NMGLatLng, data: Any, leftText: String, rightText: String) {
3349
marker = NMFMarker()
3450
marker.position = position
@@ -38,35 +54,45 @@ public final class ESMarker {
3854
updateImage()
3955
}
4056

41-
// MARK: - Methods
57+
// MARK: - Methods (기능 구현)
4258

59+
/// 마커의 위치를 변경하는 함수
60+
/// - Parameter newPosition: 새롭게 설정할 위치 (위도, 경도)
4361
public func updatePosition(newPosition: NMGLatLng) {
4462
marker.position = newPosition
4563
}
4664

65+
/// 왼쪽 말풍선의 텍스트를 업데이트하는 함수
66+
/// - Parameter newLeftText: 변경할 새로운 왼쪽 텍스트
4767
public func updateLeftText(newLeftText: String) {
4868
leftText = newLeftText
4969
updateImage()
5070
}
5171

72+
/// 오른쪽 말풍선의 텍스트를 업데이트하는 함수
73+
/// - Parameter newRightText: 변경할 새로운 오른쪽 텍스트
5274
public func updateRightText(newRightText: String) {
5375
rightText = newRightText
5476
updateImage()
5577
}
5678

79+
/// 마커의 이미지를 업데이트하여 현재 텍스트가 반영되도록 설정
5780
private func updateImage() {
5881
let image = ESMarker.createESMarkerImage(leftText: leftText, rightText: rightText)
5982
marker.iconImage = NMFOverlayImage(image: image)
6083
marker.width = image.size.width
6184
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) // 마커의 하단 중심을 지도 좌표에 맞춰 배치
6386
}
6487

88+
/// 좌우 텍스트를 포함하는 말풍선 형태의 이미지를 생성
89+
/// - Parameters:
90+
/// - leftText: 왼쪽 말풍선의 텍스트
91+
/// - rightText: 오른쪽 말풍선의 텍스트
92+
/// - Returns: 생성된 UIImage 객체
6593
private static func createESMarkerImage(leftText: String, rightText: String) -> UIImage {
66-
// Font
6794
let font = EATSSUDesignFontFamily.Pretendard.regular.font(size: 12)
6895

69-
// Text Attributes
7096
let leftAttributes: [NSAttributedString.Key: Any] = [
7197
.font: font,
7298
.foregroundColor: UIColor.systemMint,
@@ -76,74 +102,77 @@ public final class ESMarker {
76102
.foregroundColor: UIColor.black,
77103
]
78104

79-
// Text Size Calculation
105+
// 텍스트 크기 계산
80106
let leftTextSize = (leftText as NSString).size(withAttributes: leftAttributes)
81107
let rightTextSize = (rightText as NSString).size(withAttributes: rightAttributes)
82108

83-
// Bubble Dimensions
109+
// 말풍선 크기 계산
84110
let leftBubbleWidth = leftTextSize.width + Layout.horizontalPadding * 2
85111
let leftBubbleHeight = leftTextSize.height + Layout.verticalPadding * 2
86112
let rightBubbleWidth = rightTextSize.width + Layout.horizontalPadding * 2
113+
let rightBubbleHeight = rightTextSize.height + Layout.verticalPadding * 2
87114

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
91119

92-
// Image Rendering
120+
let bubbleHeight = max(leftBubbleHeight, rightBubbleHeight)
121+
122+
// 배경 높이를 말풍선보다 5 크게 설정
123+
let totalHeight = bubbleHeight + 5
124+
125+
// 이미지 렌더러 설정
93126
let renderer = UIGraphicsImageRenderer(size: CGSize(width: totalWidth, height: totalHeight))
94127
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+
)
98134
UIColor.white.setFill()
99135
backgroundPath.fill()
100136

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
110139

111-
// 2. Left Bubble
140+
// 왼쪽 말풍선 (연한 민트색 배경)
112141
let leftBubbleRect = CGRect(
113142
x: Layout.leftBubblePadding,
114-
y: 0,
143+
y: bubbleTop,
115144
width: leftBubbleWidth,
116145
height: bubbleHeight
117146
)
118147
let leftBubblePath = UIBezierPath(roundedRect: leftBubbleRect, cornerRadius: Layout.cornerRadius)
119148
UIColor.systemMint.withAlphaComponent(0.2).setFill()
120149
leftBubblePath.fill()
121150

122-
// Left Text Position
151+
// 왼쪽 텍스트 그리기
123152
(leftText as NSString).draw(
124153
at: CGPoint(
125154
x: Layout.leftBubblePadding + Layout.horizontalPadding,
126-
y: (bubbleHeight - leftTextSize.height) / 2
155+
y: bubbleTop + (bubbleHeight - leftTextSize.height) / 2
127156
),
128157
withAttributes: leftAttributes
129158
)
130159

131-
// 3. Right Bubble
160+
// 오른쪽 말풍선 (투명한 배경)
132161
let rightBubbleRect = CGRect(
133162
x: Layout.leftBubblePadding + leftBubbleWidth + Layout.spacing,
134-
y: 0,
163+
y: bubbleTop,
135164
width: rightBubbleWidth,
136165
height: bubbleHeight
137166
)
138167
let rightBubblePath = UIBezierPath(roundedRect: rightBubbleRect, cornerRadius: Layout.cornerRadius)
139168
UIColor.clear.setFill()
140169
rightBubblePath.fill()
141170

142-
// Right Text Position
171+
// 오른쪽 텍스트 그리기
143172
(rightText as NSString).draw(
144173
at: CGPoint(
145174
x: Layout.leftBubblePadding + leftBubbleWidth + Layout.spacing + Layout.horizontalPadding,
146-
y: (bubbleHeight - rightTextSize.height) / 2
175+
y: bubbleTop + (bubbleHeight - rightTextSize.height) / 2
147176
),
148177
withAttributes: rightAttributes
149178
)

0 commit comments

Comments
 (0)