MapKit (9)
LocationDetailView 기능 추가하기
ViewModel을 하나 더 만들어 준다.
그리고 LocationDetailView에 있던 변수들을 ViewModel에 옮겨준다.
1
2
3
4
5
6
7
8
9
let columns = [GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())]
var location: DDGLocation
init(location: DDGLocation) {
self.location = location
}
이때 location은 Initializing을 해줘야한다.
1
@ObservedObject var viewModel: LocationDetailViewModel
그리고 LocationDetailView에서 viewModel을 만들어주고 이전에 사용했떤 변수가 사라졌으니 관련 에러가 나므로 viewModel을 앞에 붙여주자.
길 찾기 기능
MKMapItem을 사용한다 Docs는 여기에
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// viewModel
func getDirectionsToLocation() {
let placemark = MKPlacemark(coordinate: location.location.coordinate)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = location.name
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeWalking])
}
// LocationDetailView
Button {
viewModel.getDirectionsToLocation() // new
} label: {
LocationActionButton(color: .brandPrimary, imageName: "location.fill")
}
여기서 우리는 길안내를 할때 걸어다니는 설정으로 MKLaunchOptionsDirectionsModeWalking
을 해주었다.
이제 실행을 해보면?
이렇게 Map 앱이 새로 실행이 되면서 길안내를 해준다.
전화 기능
1
2
3
4
func callLocation() {
guard let url = URL(string: "tel://\(location.phoneNumber)") else { return }
UIApplication.shared.open(url)
}
이때 url앞에 tel://
을 붙여준다.
시뮬레이터에서는 실제로 기능이 작동하지 않으니 실제 디바이스에서 해야한다.
이때 전화연결 테스트는 우선 하드코딩으로 번호를 설정하고 그 번호로 테스트 하는걸 추천
Profile Modal
UI 디자인
ModalView를 만들어본다.
코드는 다음과 같다
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
struct ProfileModalView: View {
var body: some View {
ZStack {
VStack {
Spacer()
.frame(height: 60)
Text("Harold")
.bold()
.font(.title2)
.lineLimit(1)
.minimumScaleFactor(0.75)
Text("Test Company")
.fontWeight(.semibold)
.lineLimit(1)
.minimumScaleFactor(0.75)
.foregroundStyle(.secondary)
Text("This is my sample bio. Let's keep typing to see how long we can make this, how does the padding look.")
.lineLimit(3)
.padding()
}
.frame(width: 300,height: 230)
.background(Color(.secondarySystemBackground))
.cornerRadius(16)
.overlay (
Button {
// dismiss
} label: {
XDismissButton()
}, alignment: .topTrailing
)
Image(uiImage: PlaceholderImage.avatar)
.resizable()
.scaledToFill()
.frame(width: 110, height: 110)
.clipShape(Circle())
.shadow(color: .black.opacity(0.5), radius: 4, x: 0, y: 6)
.offset(y: -120)
}
}
}
크게 언급할만한 내용은 없다.
실행하면 다음과 같이 나온다.
Logic & Animation
우선 MockData를 하나 만들어준다.
이전에 만들어둔 CKRecord 의 location을 그대로 복사하여 다음과 같이 수정해주었다.
1
2
3
4
5
6
7
8
9
10
// 여기서 RecordType을 profile로 해준다.
static var profile: CKRecord {
let record = CKRecord(recordType: RecordType.profile)
record[DDGProfile.kFirstName] = "Test"
record[DDGProfile.kLastName] = "User"
record[DDGProfile.kCompanyName] = "Best Company Ever"
record[DDGProfile.kBio] = "This is my bio, I hope it's not too long I can't check character count"
return record
}
이제 위의 UI디자인에서 하드코딩을 했던것을 MockData를 사용하여 적용을 한다.
1
2
3
4
5
Text(profile.firstName + " " + profile.lastName)
// 생략
Text(profile.companyName)
// 생략
Text(profile.bio)
이제 애니메이션을 적용한다.
우선 Modal이 나오게끔 설정을 하기위해 ViewModel에 변수를 하나 만들어준다. @Published var isShowingProfileModal = false
그리고 LocationDetailView에서
1
2
3
4
5
6
7
8
9
LazyVGrid(columns: viewModel.columns) {
FirstNameAvatarView(
image: PlaceholderImage.avatar,
firstName: "Sean"
)
.onTapGesture { // new
viewModel.isShowingProfileModal = true
}
}
이렇게 탭을 했을때 True로 하여 값이 변경된것을 알려준다.
그리고 화면 위에 띄울것이므로 기존의 Vstack위에 ZStack을 씌워준다.
if를 통해 true일때 나오게 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
if viewModel.isShowingProfileModal {
Color(.systemBackground)
.ignoresSafeArea()
.opacity(0.9)
.transition(.opacity)
.animation(.easeOut) // Deprecated Now
.zIndex(1)
ProfileModalView(isShowingProfileModal: $viewModel.isShowingProfileModal, profile: DDGProfile(record: MockData.profile))
.transition(.opacity.combined(with: .slide))
.animation(.easeOut) // Deprecated Now
.zIndex(2)
}
그리고 다시 ModalView로 돌아와서
1
2
3
4
5
6
7
.overlay (
Button {
withAnimation { isShowingProfileModal = false }
} label: {
XDismissButton()
}, alignment: .topTrailing
)
X를 눌렀을때 false를 주어서 사라지게 한다.
Animation이 위의 코드에선 Deprecated 되어있는데 추후 수정 예정
실행하면 위와 같다.
Github: Dub-Dub-Grub Repository