Spec-Zone.ru › Kotlin 2

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

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

Подробнее о совместимости с UIKit см. в статье Интеграция с фреймворком UIKit.

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

Чтобы использовать Compose Multiplatform в приложении SwiftUI, создайте функцию Kotlin MainViewController(), которая возвращает UIViewController из UIKit и содержит код Compose Multiplatform:

fun MainViewController(): UIViewController =
    ComposeUIViewController {
        Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            Text("This is Compose code", fontSize = 20.sp)
        }
    }

ComposeUIViewController() — это библиотечная функция Compose Multiplatform, которая принимает компонуемую функцию в качестве аргумента content. Переданная таким образом функция может вызывать другие компонуемые функции, например Text().

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

Затем понадобится структура, представляющая Compose Multiplatform в SwiftUI. Создайте следующую структуру, преобразующую экземпляр UIViewController в представление SwiftUI:

struct ComposeViewController: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        return Main_iosKt.MainViewController()
    }

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

Теперь вы можете использовать структуру ComposeView в другом коде SwiftUI.

Main_iosKt.MainViewController — это сгенерированное имя. Подробнее о доступе к коду Kotlin из Swift см. на странице Взаимодействие со Swift/Objective-C.

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

ComposeView

Вы можете использовать этот компонент ComposeView в любой иерархии представлений SwiftUI и управлять его размером из кода SwiftUI.

Чтобы встроить Compose Multiplatform в существующие приложения, используйте структуру ComposeView везде, где используется SwiftUI. Пример см. в нашем примерном проекте.

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

Чтобы использовать SwiftUI в Compose Multiplatform, добавьте код Swift в промежуточный компонент UIViewController. Сейчас нельзя объявлять структуры SwiftUI напрямую в Kotlin. Вместо этого их нужно написать на Swift и передать функции Kotlin.

Для начала добавьте аргумент в функцию точки входа, чтобы создать компонент ComposeUIViewController:

@OptIn(ExperimentalForeignApi::class)
fun ComposeEntryPointWithUIViewController(
    createUIViewController: () -> UIViewController
): UIViewController =
    ComposeUIViewController {
        Column(
            Modifier
                .fillMaxSize()
                .windowInsetsPadding(WindowInsets.systemBars),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text("How to use SwiftUI inside Compose Multiplatform")
            UIKitViewController(
                factory = createUIViewController,
                modifier = Modifier.size(300.dp).border(2.dp, Color.Blue),
            )
        }
    }

В коде Swift передайте createUIViewController в функцию точки входа. Для обёртывания представлений SwiftUI можно использовать экземпляр UIHostingController:

Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: { () -> UIViewController in
    let swiftUIView = VStack {
        Text("SwiftUI in Compose Multiplatform")
    }
    return UIHostingController(rootView: swiftUIView)
})

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

UIView

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

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

В Compose Multiplatform можно реализовать представление карты с помощью компонента SwiftUI Map. Это позволяет отображать в приложении полностью интерактивные карты SwiftUI.

Для той же функции точки входа Kotlin передайте в Swift UIViewController, оборачивающий представление Map с помощью UIHostingController:

import SwiftUI
import MapKit

Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: {
    let region = Binding.constant(
        MKCoordinateRegion(
            center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
            span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
        )
    )

    let mapView = Map(coordinateRegion: region)
    return UIHostingController(rootView: mapView)
})

Теперь рассмотрим более сложный пример. Этот код добавляет к карте SwiftUI пользовательскую аннотацию и позволяет обновлять состояние представления из Swift:

import SwiftUI
import MapKit

struct AnnotatedMapView: View {
    // Manages map region state
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 51.5074, longitude: -0.1278),
        span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
    )
    // Displays a map with a custom annotation
    var body: some View {
        Map(coordinateRegion: $region, annotationItems: [Landmark.example]) { landmark in
            MapMarker(coordinate: landmark.coordinate, tint: .blue)
        }
    }
}

struct Landmark: Identifiable {
    let id = UUID()
    let name: String
    let coordinate: CLLocationCoordinate2D

    static let example = Landmark(
        name: "Big Ben",
        coordinate: CLLocationCoordinate2D(latitude: 51.5007, longitude: -0.1246)
    )
}

Затем можно обернуть эту карту с аннотацией в UIHostingController и передать её коду Compose Multiplatform:

Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: {
    return UIHostingController(rootView: AnnotatedMapView())
})

AnnotatedMapView выполняет следующие задачи:

  • Определяет представление SwiftUI Map и встраивает его в пользовательское представление под названием AnnotatedMapView.

  • Управляет внутренним состоянием положения карты с помощью @State и MKCoordinateRegion, позволяя Compose Multiplatform отображать интерактивную карту с учётом состояния.

  • Отображает на карте MapMarker с помощью статической модели Landmark, соответствующей Identifiable, что необходимо для аннотаций в SwiftUI.

  • Использует annotationItems для декларативного размещения пользовательских маркеров на карте.

  • Оборачивает компонент SwiftUI в UIHostingController, который затем передаётся в Compose Multiplatform как UIViewController.

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

В Compose Multiplatform можно реализовать представление камеры с помощью SwiftUI и компонента UIKit UIImagePickerController, обёрнутого в совместимый со SwiftUI компонент. Это позволяет запускать системную камеру и делать снимки.

Для той же функции точки входа Kotlin определите в Swift простое CameraView с помощью UIImagePickerController и встроите его с помощью UIHostingController:

Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: {
    return UIHostingController(rootView: CameraView { image in
        // Handle captured image here
    })
})

Чтобы это работало, определите CameraView следующим образом:

import SwiftUI
import UIKit

struct CameraView: UIViewControllerRepresentable {
    let imageHandler: (UIImage) -> Void
    @Environment(\.presentationMode) private var presentationMode

    init(imageHandler: @escaping (UIImage) -> Void) {
        self.imageHandler = imageHandler
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.sourceType = .camera
        picker.delegate = context.coordinator
        return picker
    }

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

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: CameraView

        init(_ parent: CameraView) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController,
                                   didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                parent.imageHandler(image)
            }
            parent.presentationMode.wrappedValue.dismiss()
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

Теперь рассмотрим более сложный пример. Этот код показывает представление камеры и отображает миниатюру сделанного снимка в том же представлении SwiftUI:

import SwiftUI
import UIKit

struct CameraPreview: View {
    // Controls the camera sheet visibility
    @State private var showCamera = false
    // Stores the captured image
    @State private var capturedImage: UIImage?

    var body: some View {
        VStack {
            if let image = capturedImage {
                // Displays the captured image
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 200)
            } else {
                // Shows placeholder text when no image is captured
                Text("No image captured")
            }

            // Adds a button to open the camera
            Button("Open Camera") {
                showCamera = true
            }
            // Presents CameraView as a modal sheet
            .sheet(isPresented: $showCamera) {
                CameraView { image in
                    capturedImage = image
                }
            }
        }
    }
}

Представление CameraPreview выполняет следующие задачи:

  • Показывает CameraView в модальном .sheet, когда пользователь нажимает кнопку.

  • Использует обёртку свойства @State для хранения и отображения сделанного снимка.

  • Встраивает собственное представление SwiftUI Image для предварительного просмотра снимка.

  • Повторно использует то же UIViewControllerRepresentable-based CameraView, что и ранее, но теснее интегрирует его с системой состояния SwiftUI.

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

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

В Compose Multiplatform можно реализовать веб-представление с помощью SwiftUI, обернув компонент UIKit WKWebView в UIViewRepresentable. Это позволяет отображать встроенный веб-контент с полноценным нативным рендерингом.

Для той же функции точки входа Kotlin определите в Swift простое WebView, встроенное с помощью UIHostingController:

Main_iosKt.ComposeEntryPointWithUIViewController(createUIViewController: {
    let url = URL(string: "https://www.jetbrains.com")!
    return UIHostingController(rootView: WebView(url: url))
})

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

import SwiftUI
import UIKit
import WebKit

struct AdvancedWebView: UIViewRepresentable {
    let url: URL
    @Binding var isLoading: Bool
    @Binding var currentURL: String

    // Creates WKWebView with navigation delegate
    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        webView.load(URLRequest(url: url))
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {}

    // Creates coordinator to handle web navigation events 
    func makeCoordinator() -> Coordinator {
        Coordinator(isLoading: $isLoading, currentURL: $currentURL)
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        @Binding var isLoading: Bool
        @Binding var currentURL: String

        init(isLoading: Binding<Bool>, currentURL: Binding<String>) {
            _isLoading = isLoading
            _currentURL = currentURL
        }

        func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation?) {
            isLoading = true
        }

        // Updates URL and indicates loading has completed
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation?) {
            isLoading = false
            currentURL = webView.url?.absoluteString ?? ""
        }
    }
}

Используйте его в представлении SwiftUI следующим образом:

struct WebViewContainer: View {
    // Tracks loading state of web view
    @State private var isLoading = false
    // Tracks current URL displayed
    @State private var currentURL = ""

    var body: some View {
        VStack {
            // Displays loading indicator while loading
            if isLoading {
                ProgressView()
            }
            // Shows current URL
            Text("URL: \(currentURL)")
                .font(.caption)
                .lineLimit(1)
                .truncationMode(.middle)

            // Embeds the advanced web view
            AdvancedWebView(
                url: URL(string: "https://www.jetbrains.com")!,
                isLoading: $isLoading,
                currentURL: $currentURL
            )
        }
    }
}

AdvancedWebView и WebViewContainer выполняют следующие задачи:

  • Создают WKWebView с пользовательским делегатом навигации для отслеживания хода загрузки и изменений URL.

  • Используют привязки SwiftUI @State для динамического обновления пользовательского интерфейса в ответ на события навигации.

  • Показывают индикатор ProgressView во время загрузки страницы.

  • Отображают текущий URL в верхней части представления с помощью компонента Text.

  • Используют UIHostingController для интеграции этого компонента в пользовательский интерфейс Compose.

Что дальше

  • Узнайте, как использовать собственную навигацию SwiftUI для системных эффектов Liquid Glass, пока Compose отображает содержимое экрана.

  • Узнайте, как можно интегрировать Compose Multiplatform с фреймворком UIKit.

10 июня 2026 г.
Специальные возможностиИнтеграция с фреймворком UIKit

© 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-swiftui-integration.html

Spec-Zone.ru

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