Spec-Zone.ru › Kotlin 2

Интеграция с фреймворком UIKit

Compose Multiplatform совместим с фреймворком UIKit. Вы можете встроить Compose Multiplatform в приложение UIKit, а также встроить нативные компоненты UIKit в Compose Multiplatform. На этой странице приведены примеры использования Compose Multiplatform в приложении UIKit и встраивания компонентов UIKit в интерфейс Compose Multiplatform.

О совместимости со SwiftUI см. в статье Интеграция с фреймворком SwiftUI.

Использование Compose Multiplatform в приложении UIKit

Чтобы использовать Compose Multiplatform в приложении UIKit, добавьте код Compose Multiplatform в любой контейнерный контроллер представления. В этом примере Compose Multiplatform используется внутри класса UITabBarController:

let composeViewController = Main_iosKt.ComposeOnly()
composeViewController.title = "Compose Multiplatform inside UIKit"

let anotherViewController = UIKitViewController()
anotherViewController.title = "UIKit"

// Set up the UITabBarController
let tabBarController = UITabBarController()
tabBarController.viewControllers = [
    // Wrap the created ViewControllers in a UINavigationController to set titles
    UINavigationController(rootViewController: composeViewController),
    UINavigationController(rootViewController: anotherViewController)
]
tabBarController.tabBar.items?[0].title = "Compose"
tabBarController.tabBar.items?[1].title = "UIKit"

После выполнения этого кода приложение должно выглядеть так:

UIKit

Для отрисовки в Compose Multiplatform необходимо явно включить высокую частоту обновления: добавьте ключ CADisableMinimumFrameDurationOnPhone в файл Info.plist приложения. Без этого приложение завершится с ошибкой во время выполнения.

Изучите этот код в примере проекта.

Использование UIKit в Compose Multiplatform

Чтобы использовать элементы UIKit в Compose Multiplatform, добавьте нужные элементы UIKit в UIKitView из Compose Multiplatform. Этот код можно написать только на Kotlin или также использовать Swift.

Представление карты

Представление карты в Compose Multiplatform можно реализовать с помощью компонента MKMapView из UIKit. Задайте размер компонента с помощью функций Modifier.size() или Modifier.fillMaxSize() из Compose Multiplatform:

UIKitView(
    factory = { MKMapView() },
    modifier = Modifier.size(300.dp),
)

После выполнения этого кода приложение должно выглядеть так:

MapView

Теперь рассмотрим более сложный пример. Этот код оборачивает UITextField из UIKit в Compose Multiplatform:

@OptIn(ExperimentalForeignApi::class)
@Composable
fun UseUITextField(modifier: Modifier = Modifier) {
    // Holds the state of the text in Compose
    var message by remember { mutableStateOf("Hello, World!") }

    UIKitView(
        factory = {
            // Creates a UITextField integrated with Compose state
            val textField = object : UITextField(CGRectMake(0.0, 0.0, 0.0, 0.0)) {
                @ObjCAction
                fun editingChanged() {
                    // Updates the Compose state when text changes in UITextField
                    message = text ?: ""
                }
            }
            // Adds a listener for text changes within the UITextField
            textField.addTarget(
                target = textField,
                action = NSSelectorFromString(textField::editingChanged.name),
                forControlEvents = UIControlEventEditingChanged
            )
            textField
        },
        modifier = modifier.fillMaxWidth().height(30.dp),
        update = { textField ->
            // Updates UITextField text from Compose state
            textField.text = message
        }
    )
}
  • Параметр factory содержит функцию editingChanged() и слушатель textField.addTarget() для обнаружения любых изменений в UITextField.

  • Функция editingChanged() аннотирована с помощью @ObjCAction, чтобы обеспечить совместимость с кодом Objective-C.

  • Параметр action функции addTarget() передаёт имя функции editingChanged(), вызывая её в ответ на событие UIControlEventEditingChanged.

  • Параметр update функции UIKitView() вызывается при изменении значения наблюдаемого состояния сообщения.

  • Функция обновляет атрибут text объекта UITextField, чтобы пользователь видел обновлённое значение.

Изучите код этого примера в нашем примере проекта.

Представление камеры

Представление камеры в Compose Multiplatform можно реализовать с помощью компонентов UIKit AVCaptureSession и AVCaptureVideoPreviewLayer.

Это позволяет приложению получать доступ к камере устройства и показывать видео с неё в режиме реального времени.

Вот пример реализации простого представления камеры:

UIKitView(
    factory = {
        val session = AVCaptureSession().apply {
            val device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)!!
            val input = AVCaptureDeviceInput.deviceInputWithDevice(device, null)!!
            addInput(input)
        }
        val previewLayer = AVCaptureVideoPreviewLayer(session)
        session.startRunning()

        object : UIView() {
            override fun layoutSubviews() {
                super.layoutSubviews()
                previewLayer.frame = bounds
            }
        }.apply {
            layer.addSublayer(previewLayer)
        }
    },
    modifier = Modifier.size(300.dp)
)

Теперь рассмотрим более сложный пример. Этот код делает снимок, добавляет метаданные GPS и отображает изображение с камеры в режиме реального времени с помощью нативного UIView:

@OptIn(ExperimentalForeignApi::class) @Composable fun RealDeviceCamera( camera: AVCaptureDevice, onCapture: (picture: PictureData.Camera, image: PlatformStorableImage) -> Unit ) { // Initializes AVCapturePhotoOutput for photo capturing val capturePhotoOutput = remember { AVCapturePhotoOutput() } // ... // Defines a delegate to capture callback: process image data, attach GPS, setup onCapture val photoCaptureDelegate = remember { object : NSObject(), AVCapturePhotoCaptureDelegateProtocol { override fun captureOutput( output: AVCapturePhotoOutput, didFinishProcessingPhoto: AVCapturePhoto, error: NSError? ) { val photoData = didFinishProcessingPhoto.fileDataRepresentation() if (photoData != null) { val gps = locationManager.location?.toGps() ?: GpsPosition(0.0, 0.0) val uiImage = UIImage(photoData) onCapture( createCameraPictureData( name = nameAndDescription.name, description = nameAndDescription.description, gps = gps ), IosStorableImage(uiImage) ) } capturePhotoStarted = false } } } // ... // Sets up AVCaptureSession for photo capture val captureSession: AVCaptureSession = remember { AVCaptureSession().also { captureSession -> captureSession.sessionPreset = AVCaptureSessionPresetPhoto val captureDeviceInput: AVCaptureDeviceInput = deviceInputWithDevice(device = camera, error = null)!! captureSession.addInput(captureDeviceInput) captureSession.addOutput(capturePhotoOutput) } } // Sets up AVCaptureVideoPreviewLayer for the live camera preview val cameraPreviewLayer = remember { AVCaptureVideoPreviewLayer(session = captureSession) } // ... // Creates a native UIView with the native camera preview layer UIKitView( modifier = Modifier.fillMaxSize().background(Color.Black), factory = { val cameraContainer = object: UIView(frame = CGRectZero.readValue()) { override fun layoutSubviews() { CATransaction.begin() CATransaction.setValue(true, kCATransactionDisableActions) layer.setFrame(frame) cameraPreviewLayer.setFrame(frame) CATransaction.commit() } } cameraContainer.layer.addSublayer(cameraPreviewLayer) cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill captureSession.startRunning() cameraContainer }, ) // ... // Creates a Compose button that executes the capturePhotoWithSettings callback when pressed CircularButton( imageVector = IconPhotoCamera, modifier = Modifier.align(Alignment.BottomCenter).padding(36.dp), enabled = !capturePhotoStarted, ) { capturePhotoStarted = true val photoSettings = AVCapturePhotoSettings.photoSettingsWithFormat( format = mapOf(AVVideoCodecKey to AVVideoCodecTypeJPEG) ) if (camera.position == AVCaptureDevicePositionFront) { capturePhotoOutput.connectionWithMediaType(AVMediaTypeVideo) ?.automaticallyAdjustsVideoMirroring = false capturePhotoOutput.connectionWithMediaType(AVMediaTypeVideo) ?.videoMirrored = true } capturePhotoOutput.capturePhotoWithSettings( settings = photoSettings, delegate = photoCaptureDelegate ) } }

Компонуемый элемент RealDeviceCamera выполняет следующие задачи:

  • Настраивает нативный предпросмотр с камеры с помощью AVCaptureSession и AVCaptureVideoPreviewLayer.

  • Создаёт UIKitView, в котором размещается пользовательский подкласс UIView, отвечающий за обновление макета и встраивание слоя предпросмотра.

  • Инициализирует AVCapturePhotoOutput и настраивает делегат для обработки съёмки.

  • Использует CLLocationManager (через locationManager), чтобы получить координаты GPS в момент съёмки.

  • Преобразует полученное изображение в UIImage, оборачивает его в PlatformStorableImage и передаёт метаданные, такие как имя, описание и местоположение GPS, с помощью onCapture.

  • Отображает круглую компонуемую кнопку для запуска съёмки.

  • Применяет настройки зеркального отображения при использовании фронтальной камеры, чтобы селфи выглядело привычно.

  • Динамически обновляет макет предпросмотра в layoutSubviews() с помощью CATransaction, чтобы избежать анимации.

Чтобы проверить работу на реальном устройстве, добавьте ключ NSCameraUsageDescription в файл Info.plist приложения. Без этого приложение завершится с ошибкой во время выполнения.

Полный код этого примера можно посмотреть в примере проекта ImageViewer.

Веб-представление

Веб-представление в Compose Multiplatform можно реализовать с помощью компонента UIKit WKWebView. Это позволяет приложению отображать веб-контент и взаимодействовать с ним в интерфейсе. Задайте размер компонента с помощью функций Modifier.size() или Modifier.fillMaxSize() из Compose Multiplatform:

UIKitView(
    factory = {
        WKWebView().apply {
            loadRequest(NSURLRequest(URL = NSURL(string = "https://www.jetbrains.com")))
        }
    },
    modifier = Modifier.size(300.dp)
)

Теперь рассмотрим более сложный пример. Этот код настраивает веб-представление с делегатами навигации и обеспечивает взаимодействие между Kotlin и JavaScript:

@Composable
fun WebViewWithDelegate(
    modifier: Modifier = Modifier,
    initialUrl: String = "https://www.jetbrains.com",
    onNavigationChange: (String) -> Unit = {}
) {
    // Creates a delegate to listen for navigation events
    val delegate = remember {
        object : NSObject(), WKNavigationDelegateProtocol {
            override fun webView(
                webView: WKWebView,
                didFinishNavigation: WKNavigation?
            ) {
                // Updates the current URL after navigation is complete
                onNavigationChange(webView.URL?.absoluteString ?: "")
            }
        }
    }
    UIKitView(
        modifier = modifier,
        factory = {
            // Instantiates a WKWebView and sets its delegate
            val webView = WKWebView().apply {
                navigationDelegate = delegate
                loadRequest(NSURLRequest(uRL = NSURL(string = initialUrl)))
            }
            webView
        },
        update = { webView ->
            // Reloads the web page if the URL changes
            if (webView.URL?.absoluteString != initialUrl) {
                webView.loadRequest(NSURLRequest(uRL = NSURL(string = initialUrl)))
            }
        }
    )
}

Компонуемый элемент WebViewWithDelegate выполняет следующие задачи:

  • Создаёт стабильный объект-делегат, реализующий интерфейс WKNavigationDelegateProtocol. Этот объект сохраняется между рекомпозициями с помощью remember из Compose.

  • Создаёт экземпляр WKWebView, встраивает его с помощью UIKitView и настраивает, назначая сохранённый делегат.

  • Загружает начальную веб-страницу, указанную в параметре initialUrl.

  • Отслеживает изменения навигации через делегат и передаёт текущий URL через обратный вызов onNavigationChange.

  • Использует параметр update для отслеживания изменений запрошенного URL и соответствующей перезагрузки веб-страницы.

Что дальше

Также вы можете узнать, как интегрировать Compose Multiplatform с фреймворком SwiftUI.

19 марта 2026 г.
Интеграция с фреймворком SwiftUILiquid Glass в приложении Compose Multiplatform

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/multiplatform/compose-uikit-integration.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API