# iOS | Swift/--- SwiftUI

SwiftUI Tutorials_ Image Picker

jiniz.ll 2022. 11. 21. 15:30

 

KavSoft 채널의 튜토리얼에 대한 내용을 하나씩 해보면서 SwiftUI에 대해 공부해보려고 합니다.

따라서 이 글은 위 튜토리얼에 대한 정리 글입니다.

 

  • Xcode 14.1
  • iOS 16.1

 

** 코드는 일부 수정하여 영상과 조금 다를 수 있습니다.

 

이번 내용은 SwiftUI에서 Image Picker를 사용하기 위한 방법에 대해 학습합니다.

이 예제에서는 UIViewControllerRepresentable을 통해 이미지 피커를 띄우지만 ImagePicker에 대해 조금 알아본 결과 최근(?) PhotoPicker가 생긴 듯합니다. 그래서 우선 이번 예제를 정리해보고 PhotoPicker를 사용해서 구현해보려고 합니다.

 

(처음 Data와 관련된 부분이 계속 에러가 나길래 이런 함수가 없는건가 싶었는데,, 이전 예제에서 Data로 선언했던 것 때문이었다.. )

빈 데이터를 생성하는 방법에는 여러가지가 있는 듯 하다. 이 예제에서 처음에는 init(capacity:) 를 사용했으나 이후 init(count:)로 변경한다. 설명만 봐서는 큰 차이가 없어보이는데 (그리고 실제로도 둘 다 잘 동작한다) 뭐가 다른지는 잘 모르겠다.

 

참고.
Data. A byte buffer in memory
- init(capacity: Int)
Creates an empty data buffer of a specified size
-> 데이터의 크기
- init(count: Int)
Creates a new data buffer with the specified count of zeroed bytes
-> 바이트 수

 

강의에서 Image에 사용된 modifier 중 cornerRadius를 padding 아래에 설정한다. 하지만 해당 위치에서는 적용되지 않기 때문에 다른 위치로 옮겨 주어야 한다. 아래 구현 내용은 이미지를 원 모양으로 보여주도록 설정하였다.

 

이미지 아래에는 이미지 피커를 띄우기 위한 버튼이 있다. 시트를 보여줄지 여부를 결정하는 shown 변수를 두고 PickerViewController를 띄운다.

struct ImagePicker: View {
    
    @State private var imageData = Data(count: 0)
    @State private var shown = false
    
    private let size: CGFloat = 300
    
    var body: some View {
        VStack {
            if imageData.count != 0 {
                Image(uiImage: UIImage(data: imageData)!)
                    .resizable()
                    .frame(width: size, height: size)
                    .cornerRadius(size / 2)
                    .padding()
            }

            Button {
                shown.toggle()
            } label: {
                Text("Select Image")
            }
            .sheet(isPresented: $shown) {
                PickerViewController(shown: $shown, imageData: $imageData)
            }
        }
        .animation(.spring(), value: imageData)
    }
}

 

이전 ViewRepresentable을 사용했던 것과 유사하게 Controller를 사용하기 위해선 UIViewControllerRepresentable을 채택해야 한다. 작성방식은 유사하다. 

 

필수적으로 makeUIViewController()와 updateUIViewController를 정의해야하고 delegate 사용을 위해서 Coordinator가 필요하다. 이전 UIKit에서도 이미지 피커를 사용해보지 않았던 것 같은데...(아마도..?) 이미지 피커를 사용하기 위해서는 UIImagePickerControllerDelegate와 UINavigationControllerDelegate가 필요한 모양이다. 

 

이때 Coordinator의 init에서 변수명 앞에 _ 를 사용하는 이유는 바인딩 값을 그대로 전달하기 위해서 _ 를 사용하는 것이 규칙이기 때문이다. 사용하지 않으면 아마 값만 전달되었던 것 같다.

그 외에 UIImagePickerController에서 취소 버튼을 눌렀을 때 shown의 부울 값을 토글해주거나 이미지를 선택했을 때 해당 이미지를 jpeg 데이터로 가져온뒤 컨트롤러를 닫도록 구현하고 있다.

struct PickerViewController: UIViewControllerRepresentable {
    
    @Binding var shown: Bool
    @Binding var imageData: Data
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(imageData: $imageData, shown: $shown)
    }
    
    func makeUIViewController(context: Context) -> UIImagePickerController {
        
        let controller = UIImagePickerController()
        controller.sourceType = .photoLibrary
        controller.delegate = context.coordinator
        return controller
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
        
    }
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        @Binding var imageData: Data
        @Binding var shown: Bool
        
        init(imageData: Binding<Data>, shown: Binding<Bool>) {
            self._imageData = imageData
            self._shown = shown
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            
            shown.toggle()
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            let image = info[.originalImage] as! UIImage
            imageData = image.jpegData(compressionQuality: 80)!
            shown.toggle()
        }
    }
}

 

 

'# iOS | Swift > --- SwiftUI' 카테고리의 다른 글

[공식문서] SwiftUI_ ContextMenu  (0) 2022.11.16
SwiftUI Tutorials_ Context Menu  (0) 2022.11.16
SwiftUI Tutorials_ Search Bar  (0) 2022.11.15
SwiftUI Tutorials_ TopBar Style TabView  (0) 2022.11.09
SwiftUI Tutorials_ TabView  (0) 2022.10.31