MapKit (1)
이번엔 MapKit, CloudKit을 활용한 지도앱을 만들어본다.
기본적인건 최대한 생략을 해보는걸로…
프로젝트에 클라우드 기능 추가하기
프로젝트를 생성하고
iCloud를 추가해준다.
그리고 클라우드킷을 체크해주면 Container를 추가하는 창이 뜨는데 + 버튼을 눌러 추가해주자.
App group 컨테이너 추가하듯 Identifier를 복사해서 붙이고, 앞에 icloud를 적어주었다.
그러면 CloudKit을 사용할 준비는 끝났다.
Color Asset 추가
주로 사용할 색상에 대해 추가를 해준다.
+를 클릭하고 Color Set을 추가해주자
그리고 이름은 brandPrimary로 해주었다.
그리고 순서대로 하여 색상을 추가해준다.
우측의 다크모드도 똑같이 적용해주자.
Color Extension 설정하기 (17버전 이상은 X)
1
2
3
extension Color {
static let brandPrimary = Color("brandPrimary")
}
17버전 이전에는 Asset에 추가한걸 편하게 사용하기위해 이렇게 변수를 선언했지만,
17버전 이후에는 Asset에 추가를 하면
1
2
3
4
5
6
7
8
#if canImport(SwiftUI)
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension SwiftUI.Color {
/// The "brandPrimary" asset catalog color.
static var brandPrimary: SwiftUI.Color { .init(.brandPrimary) }
}
이렇게 자동으로 추가가 된다.
TabView 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
TabView {
Tab("Map", systemImage: "map") {
LocationMapView()
}
Tab("Locations", systemImage: "building") {
LocationListView()
}
Tab("Profile", systemImage: "person") {
ProfileView()
}
}
.tint(.brandPrimary)
크게 언급할건 없어보인다.
LocationMapView 기본적인 디자인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// before 17
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.331516, longitude: -121.891054),
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
var body: some View {
ZStack {
Map(coordinateRegion: $region)
VStack {
Image("ddg-map-logo")
.resizable()
.scaledToFit()
.frame(height: 70)
.shadow(radius: 10)
Spacer()
}
}
}
// after 17
현재 coordinateRegion은 Deprecated 되었다.
수정코드는 이후에 올리는걸로.
span의 경우 값이 클수록 지도가 축소된다.
나머지 기본적인 UI디자인은 생략
Text 짤릴때 팁
1
2
3
4
5
Text("Location Name")
.font(.title2)
.fontWeight(.semibold)
.lineLimit(1)
.minimumScaleFactor(0.75)
Text가 길지도 않음에도 불구하고 이렇게 … 으로 생략된다면
1
2
3
4
5
6
Text("Location Name")
.font(.title2)
.fontWeight(.semibold)
.lineLimit(1)
.minimumScaleFactor(0.75)
.frame(maxWidth: .infinity, alignment: .leading)
최대 가로 길이를 동적으로 바꿔준다.
alignment를 설정한건 좌측정렬을 해주기 위함.
Text 구성 팁
1
2
3
4
5
VStack(alignment: .leading, spacing: 8) {
Text("Bio: 100 Characters Remain")
.font(.callout)
.foregroundStyle(.secondary)
}
Text에 대해 Bio: 100 Characters Remain
라는 문장에서, 단어별로 포인트를 주고싶을때는
아래와 같이 +_를 사용하면 Text 끼리 연결이 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
VStack(alignment: .leading, spacing: 8) {
Text("Bio: ")
.font(.callout)
.foregroundStyle(.secondary)
+
Text("100")
.bold()
.font(.callout)
.foregroundStyle(.brandPrimary)
+
Text(" Characters Remain")
.font(.callout)
.foregroundStyle(.secondary)
// 생략
}
CustomModifier 적용하기
1
2
3
4
5
6
7
8
TextField("First Name", text: $firstName)
.font(.system(size: 32, weight: .bold))
.lineLimit(1)
.minimumScaleFactor(0.75)
TextField("Last Name", text: $lastName)
.font(.system(size: 32, weight: .bold))
.lineLimit(1)
.minimumScaleFactor(0.75)
이렇게 같은 모디파이어가 중복이 될때 CustomModifier를 통해 간단하게 만들 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
struct ProfileNameText: ViewModifier {
func body(content: Content) -> some View {
content
.font(.system(size: 32, weight: .bold))
.lineLimit(1)
.minimumScaleFactor(0.75)
}
}
// 적용
TextField("First Name", text: $firstName)
.modifier(ProfileNameText())
여기서 조금 더 Modifier 스럽게 바꾼다면
1
2
3
4
5
extension View {
func profileNameStyle() -> some View {
self.modifier(ProfileNameText())
}
}
이렇게 extension으로 해준다.
1
2
TextField("Last Name", text: $lastName)
.profileNameStyle()
이젠 Modifier처럼 사용이 가능하다.
기본적인 UI디자인 파트가 많아서 생략을 많이했다.
완성된 초기 UI는 위와 같다.
Github: Dub-Dub-Grub Repository