티스토리 뷰

iOS/SwiftUI

[SwiftUI] - ImagePicker 사용

강철곰탱이 2024. 2. 1. 02:45

 

 

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에 대한 바인딩이다. 다른 뷰의 표시 또는 해제를 제어하는 ​​데 자주 사용된다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
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
글 보관함