Published on

SwiftUI'da UIKit ekranlarini ishlatish (UIViewControllerRepresentable)

Authors

Nima uchun ViewController kerak?

Oldingi darsda biz bitta oddiy UITextField ni UIViewRepresentable yordamida SwiftUI ga o'tkazgandik. Lekin ba'zida bizga tayyor to'liq oyna (ekran) kerak bo'lib qoladi. Eng yaxshi misol — Kamera yoki Rasmlar galereyasi (UIImagePickerController). Hali ham ko'p dasturchilar rasmlarni tanlash uchun UIKit'ning ushbu ochiq va moslashuvchan Controller'idan foydalanishadi.

Uni SwiftUI ga olib kirish uchun biz UIViewControllerRepresentable dan foydalanamiz.

1. Oddiy view controller yaratish

Avval eng sodda holatni ko'raylik. O'zimiz custom yasagan yoki tayyor UIViewController ni SwiftUI'da .sheet yoki NavigationLink yordamida ochmoqchimiz.

import SwiftUI

struct BasicUIViewControllerRepresentable: UIViewControllerRepresentable {
    let labelText: String

    // 1. Controller'ni yaratamiz
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIViewController()
        vc.view.backgroundColor = .blue

        // Ekranga bitta yozuv qo'shamiz
        let label = UILabel()
        label.text = labelText
        label.textColor = .white
        label.frame = vc.view.frame
        vc.view.addSubview(label)

        return vc
    }

    // 2. SwiftUI dagi o'zgarishlarga qarab uni yangilaymiz
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        // Hozircha bo'sh
    }
}

Buni istalgan SwiftUI tugmasi orqali ochish mumkin:

Button("Oynani ochish") {
    showScreen.toggle()
}
.sheet(isPresented: $showScreen) {
    BasicUIViewControllerRepresentable(labelText: "Yangi UIKit Oynasi!")
}

2. Rasmlar Galereyasini (UIImagePickerController) ulash

Haqiqiy muammo biz UIKit dagi galereyani ochib, u yerdan tanlangan rasmni SwiftUI ga qaytarib olmoqchi bo'lganimizda boshlanadi. Buning uchun biz yana Coordinator (Vositachi) dan foydalanamiz.

struct UIImagePickerControllerRepresentable: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Binding var showScreen: Bool

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let vc = UIImagePickerController()
        vc.allowsEditing = false

        // Vositachini tayinlaymiz!
        vc.delegate = context.coordinator
        return vc
    }

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

    // Vositachini yaratish
    func makeCoordinator() -> Coordinator {
        return Coordinator(image: $image, showScreen: $showScreen)
    }

    // Delegate metodlarini ushlaydigan Coordinator Class
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        @Binding var image: UIImage?
        @Binding var showScreen: Bool

        init(image: Binding<UIImage?>, showScreen: Binding<Bool>) {
            self._image = image
            self._showScreen = showScreen
        }

        // Rasm tanlanganda avtomat ishlaydi
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

            // Tanlangan rasmni olamiz
            if let newImage = info[.originalImage] as? UIImage {
                self.image = newImage // Uni SwiftUI ga beramiz
            }

            // Va galereyani yopamiz
            self.showScreen = false
        }
    }
}

Qanday foydalaniladi?

Endi SwiftUI sahifamizda bitta @State rasm obyekti yaratamiz va galereya qaytargan rasmni shu yerda ko'rsatamiz:

struct ImagePickerBootcamp: View {
    @State private var showScreen: Bool = false
    @State private var selectedImage: UIImage? = nil

    var body: some View {
        VStack {
            if let image = selectedImage {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200)
            }

            Button("Rasm tanlash") {
                showScreen.toggle()
            }
        }
        .sheet(isPresented: $showScreen) {
            UIImagePickerControllerRepresentable(image: $selectedImage, showScreen: $showScreen)
        }
    }
}

Xulosa: SwiftUI dagi ilovangizda tayyor UIKit imkoniyatlaridan (Kamera, Fayllar, Xaritalar) to'liq foydalanish imkoniyatini UIViewControllerRepresentable orqali hech qanday qiyinchiliksiz qila olasiz. Coordinator tushunchasi esa ular o'rtasida ishonchli ko'prik vazifasini o'taydi.

Buy mea coffee