Published on

PhotosPicker va PhotosUI (Galereyadan rasm tanlash)

Authors

Galereya bilan ishlashning eski usuli qanday edi?

SwiftUI paydo bo'lgan dastlabki yillarda ilovamizga oddiygina rasm tanlash funksiyasini qo'shish uchun UIKit ning UIImagePickerController sini UIViewControllerRepresentable orqali ulashimiz kerak bo'lardi. Bu o'nlab qator tushunarsiz va murakkab kodlarni talab etardi.

Nihoyat, Apple bizga toza va 100% SwiftUI'da ishlaydigan tayyor yechim – PhotosPicker ni taqdim etdi! U PhotosUI freymvorki ichida joylashgan.

Bitta rasm tanlash (Single Selection)

Buning uchun avvalo eng tepada modulni chaqiramiz: import PhotosUI.

ViewModel'imiz ichida foydalanuvchi tanlagan ma'lumotni ushlab turish uchun maxsus PhotosPickerItem tipidagi o'zgaruvchi ochamiz. E'tibor bering, bu hali Rasm (Image) emas, shunchaki rasm haqida ma'lumot!

import SwiftUI
import PhotosUI

@MainActor
class PhotoPickerViewModel: ObservableObject {
    // Tanlangan ma'lumot (Hali Rasm emas)
    @Published var imageSelection: PhotosPickerItem? = nil {
        didSet {
            // Har safar ma'lumot tanlanganda rasmni yuklash funksiyasini chaqiramiz
            setImage(from: imageSelection)
        }
    }

    // Ekranda ko'rsatiladigan haqiqiy rasm
    @Published var selectedImage: UIImage? = nil

    // 💡 ASOSIY ASINXRON QISMI:
    private func setImage(from selection: PhotosPickerItem?) {
        guard let selection else { return }

        Task {
            // loadTransferable() orqali rasmni 'Data' ga aylantiramiz
            if let data = try? await selection.loadTransferable(type: Data.self) {
                // Data ni yana qayta UIImaga'ga o'tkazamiz
                if let uiImage = UIImage(data: data) {
                    self.selectedImage = uiImage
                }
            }
        }
    }
}

View (Ekran) qismi esa nihoyatda oson:

struct PhotoPickerView: View {
    @StateObject private var vm = PhotoPickerViewModel()

    var body: some View {
        VStack {
            // Agar rasm tanlangan bo'lsa uni ko'rsatamiz
            if let image = vm.selectedImage {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFill()
                    .frame(width: 200, height: 200)
                    .clipShape(RoundedRectangle(cornerRadius: 10))
            }

            // 💡 Sehrli qator: PhotosPicker
            PhotosPicker(
                selection: $vm.imageSelection,
                matching: .images, // Faqat rasmlarni tanlashga ruxsat (Videolarga emas)
                photoLibrary: .shared()) {
                    Text("Galereyani ochish")
                        .foregroundColor(.blue)
            }
        }
    }
}

Ko'p rasm tanlash (Multiple Selection)

Agar bir vaqtning o'zida birdaniga bir nechta rasmni tanlash kerak bo'lsa-chi? (Masalan, Telegramda rasmlar jo'natishdek).

Bu ham xuddi shunday ishlaydi, faqat o'zgaruvchilar massiv (Array) ko'rinishida bo'ladi:

@MainActor
class MultiplePhotoPickerViewModel: ObservableObject {
    // Endi bitta emas, Ko'p tanlovlar massivi
    @Published var imageSelections: [PhotosPickerItem] = [] {
        didSet {
            setImages(from: imageSelections)
        }
    }

    // Tanlangan ko'plab rasmlar
    @Published var selectedImages: [UIImage] = []

    private func setImages(from selections: [PhotosPickerItem]) {
        Task {
            var images: [UIImage] = []

            // Massivdagi har birini alohida yuklab olamiz
            for selection in selections {
                if let data = try? await selection.loadTransferable(type: Data.self),
                   let uiImage = UIImage(data: data) {
                    images.append(uiImage)
                }
            }

            self.selectedImages = images
        }
    }
}

View qismida faqatgina bog'lanish (Binding) imageSelections ga o'zgaradi xolos:

PhotosPicker(
    selection: $vm.imageSelections, // Massivga ulangan!
    maxSelectionCount: 5, // Ixtiyoriy: Eng ko'pi 5 ta rasm
    matching: .images
) {
    Text("Ko'p rasm tanlash")
}

Nega rasm avval "Item", keyin "Data", oxirida "Image" ga o'zgardi?

Buning sababi – zamonaviy iOS'da Galereya (Photos) da faqat rasmlar emas, balki videolar, Live Photo lar va RAW formatlar ham bor. Obyekt har qanday turda bo'lishi mumkinligi uchun kompyuterga biz aynan faylning Data.self shaklini (asl xotira ko'rinishini) asinxron tarzda so'rayotganimizni tushuntirishimiz kerak bo'ladi. U kelganidan keyin esa, bemolol UIImage ga qadoqlab ishlatib ketaveramiz.

Ushbu jarayon faqat Async/Await va Swift Concurrency yordamida ilovani "qotirib qo'ymasdan" silliq ishlay oladi.

Buy mea coffee