티스토리 뷰
ImagePicker 사용
📍 기능
- ImagePicker로 image 선택
- TextField에 text 입력
- NavigationLink로 화면 넘어가 등록된 데이터 보여주기
1️⃣ UserData 포맷 설정
import SwiftUI
struct UserData {
var name: String
var profileImage: UIImage?
}
2️⃣ UI 구현
- NavigationView 사용
NavigationView | Apple Developer Documentation
A view for presenting a stack of views that represents a visible path in a navigation hierarchy.
developer.apple.com
- UserProfileView
: NavigationView에 title 설정과 오른쪽 item 넣기
struct UserProfileView: View {
@State private var userData: UserData = UserData(name: "", profileImage: nil)
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 20) {
Button(action: {
}, label: {
let image = userData.profileImage == nil ? Image(systemName: "person.circle.fill") : Image(uiImage: userData.profileImage!)
image
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())//원 모양
})
TextField("Enter your username", text: $userData.name)
.multilineTextAlignment(.center)//중앙 정렬
Spacer()
}
.padding(.top, 50)
.navigationBarTitle("User Profile", displayMode: .inline)
.navigationBarItems(trailing:
NavigationLink(destination: RegisteredUserView(userData: userData)) {//NavigationLink 연결
Text("Sign Up")
}
)
}
}
}
- RegisteredUserView
: NavigationLink로 넘어온 View
struct RegisteredUserView: View {
var userData: UserData
var body: some View {
VStack(alignment: .center, spacing: 20) {
Image(uiImage: userData.profileImage!)
.resizable()
.frame(width: 200, height: 200)
.clipShape(Circle())
Text(userData.name)
.multilineTextAlignment(.center)
Spacer()
}
.padding(.top, 50)
}
}
3️⃣ ImagePicker 적용
- UserProfileView
: .sheet로 isPresented의 bool 값으로 ImagePickerView를 보여준다.
✏️ .sheet
: SwiftUI에서 모달 시트를 표시하는 데 사용된다. Bool 값(isPresented)에 대한 바인딩을 취하고 Bool 값이 true가 되면 시트가 표시된다. Bool 값이 false가 되면 시트가 닫힌다.
import SwiftUI
struct UserProfileView: View {
@State private var imagePickerPresented = false
@State private var userData: UserData = UserData(name: "", profileImage: nil)
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 20) {
Button(action: {
imagePickerPresented.toggle()
}, label: {
let image = userData.profileImage == nil ? Image(systemName: "person.circle.fill") : Image(uiImage: userData.profileImage!)
image
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())
})
TextField("Enter your username", text: $userData.name)
.multilineTextAlignment(.center)
Spacer()
}
.padding(.top, 50)
.navigationBarTitle("User Profile", displayMode: .inline)
.navigationBarItems(trailing:
NavigationLink(destination: RegisteredUserView(userData: userData)) {
Text("Sign Up")
}
)
.sheet(isPresented: $imagePickerPresented) {
ImagePickerView(selectedImage: $userData.profileImage, presentationMode: _presentationMode)
}
}
}
}
- ImagePickerView
UIViewControllerRepresentable | Apple Developer Documentation
A view that represents a UIKit view controller.
developer.apple.com
✏️ UIViewControllerRepresentable
: SwiftUI 뷰 계층 구조에서 UIKit UIViewController를 표현할 수 있게 해주는 SwiftUI의 프로토콜
ImaePicker를 사용하기 위해 UIImagePickerController를 사용해야 한다. 하지만 uikit의 ViewController이므로, UIViewControllerRepresentable을 적용해서 UIImagePickerController를 SwiftUI에서 사용할 수 있도록 한다.
1. makeCoordinator
: Coordinator 클래스의 인스턴스를 생성하기 위해 호출
2. makeUIViewController
: UIImagePickerController의 인스턴스를 생성하고 반환
3. updateUIViewController
: uikit의 ViewController를 나타내는 SwiftUI view를 업데이트해야 할 때마다 호출된다.
(사용 안해서 제외)
struct ImagePickerView: UIViewControllerRepresentable {
@Binding var selectedImage: UIImage?
@Environment(\.presentationMode) var presentationMode
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePickerView
init(parent: ImagePickerView) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.selectedImage = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
- Coordinator
🔎 Coordinator 란?
: UIKit 세계와 SwiftUI 세계 사이의 다리 역할을 하며 둘 사이의 통신과 이벤트를 관리한다.
이름은 무조건 "Coordinator"로 해야한다.
NSObject와 uikit에서 ImagePicker의 delegate인 UIImagePickerControllerDelegate, UINavigationControllerDelegate를 상속받는다.
NSObject: 모든 Objective-C 클래스의 기본 클래스이며 Objective-C 런타임 기능과의 호환성을 제공
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePickerView
init(parent: ImagePickerView) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.selectedImage = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
✏️ @Binding과 @Environment
1. @Binding
: 뷰와 상위 뷰 간의 양방향 연결을 만드는 데 사용, 이를 통해 상위 뷰는 UIImage를 이 속성에 전달할 수 있으며 하위 뷰 내에서 변경된 내용은 상위 뷰에 반영된다.
2. @Environment
: @Environment는 SwiftUI 환경의 값에 액세스하는 데 사용, 환경은 값을 매개변수로 명시적으로 전달하지 않고 뷰 계층 구조 아래로 값을 전달하는 방법이다.
@Environment를 사용하여 PresentationMode 환경 값에 액세스한다. 이 값은 뷰가 현재 표시되고 있는지 여부를 나타내는 Bool에 대한 바인딩이다. 다른 뷰의 표시 또는 해제를 제어하는 데 자주 사용된다.
'iOS > SwiftUI' 카테고리의 다른 글
[SwiftUI] - Navigation bar 제외한 background Color 설정 (0) | 2024.02.11 |
---|---|
[SwiftUI] - Todo List 구현 (0) | 2024.02.07 |
[Swift] SwiftUI StopWatch 구현 (0) | 2024.01.22 |
[SwiftUI] - Apple 로그인 구현 (0) | 2024.01.06 |
[SwiftUI] - 구글 로그인 구현 (0) | 2023.12.09 |