MapKit (15)
Custom Map Annotation
Annotation을 만들어 보려고 한다.
1
2
3
4
5
6
struct MapBalloon: Shape {
func path(in rect: CGRect) -> Path {
return path
}
}
여기서 한가지 흥미로운 점이라면 View가 아닌 Shape로 만들었다는 것이다.
여기 보면 Shape도 하나의 View이다. Shape Docs참고
포인트는
- 자동 색상 채우기 (Default Fill)
- 도형에
.fill()이나.stroke()를 따로 지정하지 않으면, 시스템이 알아서 현재 포그라운드 컬러(Foreground Color)를 가져와 내부를 채운다. 즉, 아무 설정 없어도 기본적으로 색이 칠해진 상태로 나타난다.
- 도형에
- 도형을 그리는 두 가지 방식
- 상대적 정의 (Implicit Frame): 자기를 담고 있는 뷰(Container)의 크기에 맞춰서 모양을 결정한다. (예:
Capsule,Circle처럼 부모 뷰 크기에 꽉 차게 그려지는 경우) - 절대적 정의 (Absolute Coordinates): 부모 뷰 크기와 상관없이
(x: 10, y: 50)같은 고정된 좌표값으로 모양을 그린다. (예:Path를 직접 그리는 경우)
- 상대적 정의 (Implicit Frame): 자기를 담고 있는 뷰(Container)의 크기에 맞춰서 모양을 결정한다. (예:
이다.
이때 한가지 중요한건
Shape의 경우 path라는 함수가 반드시 필요하다.
path라는 함수를 통해서 우리가 디자인을 하게 된다.
한마디로 path는 하나의 디자인 경로?의 느낌이랄까 어떤 점이 path를 통해 움직이면서 하나의 shape를 만드는 느낌으로 이해하면 좋을듯
shape가 만들어지는 기본 메커니즘 정리
path.move(to: CGPoint(x: rect.minX, y: rect.maxY)) 는
shape를 그릴 시작 지점을 옮겨주는 걸로 이해하면 된다.
예를 들어 아래와 같이 코드를 작성했다면? 결과는 어떻게 될까?
1
2
3
path.move(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
우선 하나하나 알아보자. move는 패스해도 될것같고, 두번째 addLine은 제일 왼쪽 하단에서 y축 중간까지 선을 긋는다는 것.
그리고 세번째 addLine은 y축중간에서 x가 우측으로 끝까지 간다는 것
위와 같이 코드를 작성하고 확인해보면 아래 쪽에 삼각형이 생기는걸 알 수 있다.
그럼 왜 삼각형일까? 를 생각을 해보면 우리는 시작점이 어딘지를 먼저 생각해 볼 필요가 있다.
사진과 같이 좌측 하단에서 시작을 해서 우측 중앙까지 선이 이동 했기에 ⌜의 형태로 이동을 했다. 그 이후로 어떠한 명령이 없기에 마지막 지점에서 다시 시작지점으로 선이 이동한것.
그렇다면
1
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
이게 추가된다면?
이건 뭐 사진을 굳이 추가할필요는 없을듯 하다. 보나마나 사각형이 만들어 질것이다.
frame을 넣어서 사이즈를 우리가 정하게 된다면?
그 프레임을 기준으로 알아서 움직여서 도형이 그려질것이다. 혹시라도 이해가 조금 어렵다면 border를 사용하여 보더라인을 그려보면 이해가 쉬울것으로 생각된다.
1
2
3
4
5
#Preview {
MapBalloon()
.frame(width: 300, height: 300)
.border(.black)
}
좀 더 다양한 shape를 그려보고 싶다면
위의 유튜브를 한번 보는것도 좋을듯?
quadcurve를 사용하여 annotaion mark 만들기
quadcurve에 대해선 addQuadCurve Docs의 사진을 보면 이해하기 쉽다.
1
2
3
4
5
path.move(to: CGPoint(x: rect.midX, y: rect.maxY))
path.addQuadCurve(to: CGPoint(x: rect.midX, y: rect.minY),
control: CGPoint(x: rect.minX, y: rect.minY))
path.addQuadCurve(to: CGPoint(x: rect.midX, y: rect.maxY),
control: CGPoint(x: rect.maxX, y: rect.minY))
이렇게 된다. (preview에서 frame을 통해 사이즈와 color를 설정해둔 상태)
Annotation View 만들기
위에서 만든 shape를 활용하여 이렇게 annotation view를 만들어 보도록 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct DDGAnnotation: View {
var location: DDGLocation
var body: some View {
VStack {
ZStack {
MapBalloon()
.frame(width: 100, height: 70)
.foregroundColor(.brandPrimary)
Image(uiImage: location.createSquareImage())
.resizable()
.frame(width: 40, height: 40)
.clipShape(Circle())
.offset(y: -11)
Text("99")
.font(.system(size: 11, weight: .bold))
.frame(width: 26, height: 18)
.background(Color.grubRed)
.foregroundColor(.white)
.clipShape(Capsule())
.offset(x: 20, y: -28)
}
Text(location.name)
.font(.caption)
.fontWeight(.semibold)
}
}
}
이렇게 잘 나오는걸 알 수 있다. (현재는 preview에서 MockData를 사용한 상태)
Github: Dub-Dub-Grub Repository