[swiftUI] SwiftUI에서 UIImagePickerController 사용하기

2026. 5. 21. 14:52·swiftUI

공식문서: https://developer.apple.com/documentation/uikit/uiimagepickercontroller

UIImagePickerController

UIImagePickerController는 iOS 앱 내에서 사진이나 동영상을 촬영하거나, 기기의 사진 라이브러리에서 이미지를 선택할 수 있도록 시스템 기본 UI를 제공하는 뷰 컨트롤러입니다.

주요 모드(Source Type)

이 컨트롤러의 화면과 역할은 표시하기 전에 설정하는 소스 타입(Source Type)에 따라 달라집니다.

  • .camera: 새로운 사진이나 동영상을 촬영할 수 있는 카메라 인터페이스를 제공합니다.
  • .photoLibrary/.savedPhotoAlbum: 기기에 저장된 기존 사진과 동영상을 고를 수 있는 앨범 인터페이스를 제공합니다.

기본 사용 방법

  1. 지원 여부 확인: isSourceTypeAvailable 메서드를 사용해 현재 기기에서 카메라나 사진첩 접근이 가능한지 먼저 확인합니다.
  2. 미디어 타입 설정: 사진만 고르게 할 것인지 동영상도 고르게 할 것인지 mediaTypes 속성을 통해 설정합니다.
  3. 화면 띄우기(Present):
    • iPhone: 모달 방식으로 띄움
    • iPad: 카메라는 전체화면을 사용할 수 있지만 사진첩 앨범을 띄울 때는 반드시 팝업 형태로 띄워야 함
  4. 결과 처리(Delegate): 사용자가 사진을 선택하거나 취소 버튼을 눌렀을 때의 동작을 처리하기 위해 UIImagePickerControllerDelegate를 설정하여 결과값을 넘겨받습니다.

주의사항

  • 기본적으로 세로(Portrait) 모드만 지원합니다.
  • 기본 UI를 사용하고 싶지 않다면 해당 클래스 대신 AVFoundation이나 PhotoKit 프레임워크를 사용해야 합니다.

데모 앱

import SwiftUI
import UIKit
import UniformTypeIdentifiers

struct ContentView: View {
    // 선택하거나 촬영한 이미지를 SwiftUI 화면에 표시하기 위한 상태값입니다.
    @State private var selectedImage: UIImage?

    // 하나의 UIImagePickerController로 카메라와 사진첩을 번갈아 열기 위해 sourceType을 저장합니다.
    @State private var pickerSource: UIImagePickerController.SourceType = .photoLibrary
    @State private var isShowingPicker = false

    // 시뮬레이터처럼 카메라를 사용할 수 없는 환경을 안내하기 위한 alert 상태입니다.
    @State private var alertMessage = ""
    @State private var isShowingAlert = false

    var body: some View {
        NavigationStack {
            VStack(spacing: 24) {
                imagePreview

                VStack(spacing: 12) {
                    Button {
                        presentPicker(for: .camera)
                    } label: {
                        Label("사진 촬영", systemImage: "camera")
                            .frame(maxWidth: .infinity)
                    }
                    .buttonStyle(.borderedProminent)

                    Button {
                        presentPicker(for: .photoLibrary)
                    } label: {
                        Label("사진첩에서 선택", systemImage: "photo.on.rectangle")
                            .frame(maxWidth: .infinity)
                    }
                    .buttonStyle(.bordered)
                }
            }
            .padding()
            .navigationTitle("UIImagePickerController Demo")
            .toolbarTitleDisplayMode(.inline)
        }
        .sheet(isPresented: $isShowingPicker) {
            ImagePicker(sourceType: pickerSource, selectedImage: $selectedImage)
                .ignoresSafeArea()
        }
        .alert("사용할 수 없음", isPresented: $isShowingAlert) {
            Button("확인", role: .cancel) {}
        } message: {
            Text(alertMessage)
        }
    }

    private var imagePreview: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .fill(.secondary.opacity(0.12))

            if let selectedImage {
                Image(uiImage: selectedImage)
                    .resizable()
                    .scaledToFit()
                    .clipShape(RoundedRectangle(cornerRadius: 8))
            } else {
                ContentUnavailableView(
                    "선택된 이미지 없음",
                    systemImage: "photo",
                    description: Text("사진을 촬영하거나 사진첩에서 이미지를 선택하세요.")
                )
            }
        }
        .frame(maxWidth: .infinity)
        .aspectRatio(1, contentMode: .fit)
    }

    private func presentPicker(
        for sourceType: UIImagePickerController.SourceType
    ) {
        // UIImagePickerController는 기기마다 지원하는 sourceType이 다를 수 있으므로 먼저 확인합니다.
        guard UIImagePickerController.isSourceTypeAvailable(sourceType) else {
            alertMessage = sourceType == .camera
            ? "이 기기에서는 카메라를 사용할 수 없습니다."
            : "이 기기에서는 사진첩을 사용할 수 없습니다."
            isShowingAlert = true
            return
        }

        pickerSource = sourceType
        isShowingPicker = true
    }
}

// UIKit의 UIImagePickerController를 SwiftUI에서 sheet로 띄우기 위한 래퍼입니다.
struct ImagePicker: UIViewControllerRepresentable {
    let sourceType: UIImagePickerController.SourceType
    @Binding var selectedImage: UIImage?
    @Environment(\.dismiss) private var dismiss

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.sourceType = sourceType
        // 이미지 선택/촬영만 다루도록 mediaTypes를 이미지로 제한합니다.
        picker.mediaTypes = [UTType.image.identifier]
        picker.allowsEditing = false
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(
        _ uiViewController: UIImagePickerController,
        context: Context
    ) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(selectedImage: $selectedImage, dismiss: dismiss)
    }

    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        @Binding private var selectedImage: UIImage?
        private let dismiss: DismissAction

        init(selectedImage: Binding<UIImage?>, dismiss: DismissAction) {
            _selectedImage = selectedImage
            self.dismiss = dismiss
        }

        func imagePickerController(
            _ picker: UIImagePickerController,
            didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
        ) {
            // 선택 결과에서 원본 이미지를 꺼내 SwiftUI 상태값에 전달합니다.
            selectedImage = info[.originalImage] as? UIImage
            dismiss()
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            dismiss()
        }
    }
}

SwiftUI에서는 UIImagePickerController를 직접 사용할 수 없기 때문에 UIViewControllerRepresentable로 감싸서 사용했습니다. 버튼을 누르면 카메라 또는 사진첩을 sourceType으로 지정해 picker를 띄우고, 선택이 끝나면 delegate 메서드에서 originalImage를 가져와 SwiftUI의 @State값에 저장합니다. 저장된 이미지는 Image(uiImage:)로 화면에 표시합니다.

스크린샷

 

 

'swiftUI' 카테고리의 다른 글
  • [SwiftUI] Widget에 데이터 가져오기
  • [SwiftUI] Navigation BackButton Custom
GwanSon
GwanSon
귀찮음과 불편함을 해결하는 개발자가 되자.
  • GwanSon
    관슨의 개발일지
    GwanSon
  • 전체
    오늘
    어제
    • 분류 전체보기 (57)
      • iOS (5)
      • swift (16)
      • UIKit (0)
      • swiftUI (3)
      • 알고리즘 (9)
      • CS (8)
      • 면접 (0)
      • Flutter (11)
      • 회고 (3)
      • 잡담 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

  • 인기 글

  • 태그

    Riverpod
    부스트캠프
    boj
    부스트캠프 10기
    모듈화
    2025 토스 Next
    cached_network_image
    챌린지
    Flutter
    SDK
    ios
    FirebaseAuth
    후기
    fluuter
    백준
    UIImagePickerController
    go_router
    tuist
    Provider
    구슬 탈출2
    Dio
    SwiftUI
    토스
    fatal error
    네이버 부스트캠프
    ISAR
    Swift
    Firebase
    android
    네이버 부스트캠프 후기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
GwanSon
[swiftUI] SwiftUI에서 UIImagePickerController 사용하기
상단으로

티스토리툴바