← Назад к вопросам

Какие UI-компоненты можно сделать общими для Android и Desktop в KMP проекте

2.7 Senior🔥 101 комментариев
#Архитектура и паттерны#Многомодульность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Общие UI-компоненты в KMP для Android и Desktop

В KMP (Kotlin Multiplatform) проектах с использованием Compose Multiplatform можно создавать кроссплатформенные UI-компоненты, которые работают на Android, Desktop (и других платформах). Ключевой принцип — разделение кода на common (общую) и platform-specific (платформенно-специфическую) части. Вот основные категории компонентов, которые эффективно обобщаются:

1. Базовые компоненты композиции

Это примитивы Compose, которые доступны на всех платформах и составляют основу UI:

// Общий код в commonMain
@Composable
fun CustomButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Button(
        onClick = onClick,
        modifier = modifier,
        colors = ButtonDefaults.buttonColors(
            backgroundColor = MaterialTheme.colors.primary
        )
    ) {
        Text(text = text)
    }
}
  • Text, Button, TextField — базовые элементы ввода и отображения
  • Column, Row, Box — контейнеры для компоновки
  • Image (с загрузкой через общие ресурсы)
  • Card, Surface — контейнеры с оформлением

2. Составные компоненты и виджеты

Более сложные компоненты, объединяющие несколько базовых:

  • Диалоги и алерты с кастомным содержимым
  • Списки (LazyColumn/LazyRow) с общим механизмом отображения данных
  • Панели навигации и верхние панели (TopAppBar)
  • Вкладки (TabRow) с переключаемым контентом
  • Индикаторы загрузки и состояния пустых экранов

3. Компоненты с состоянием и логикой

Компоненты, инкапсулирующие бизнес-логику через Compose ViewModel или StateFlow:

// Общая ViewModel в commonMain
class SearchViewModel() : ViewModel() {
    private val _searchText = MutableStateFlow("")
    val searchText: StateFlow<String> = _searchText
    
    fun onSearchTextChanged(text: String) {
        _searchText.value = text
    }
}

// Компонент поиска
@Composable
fun SearchBar(viewModel: SearchViewModel) {
    val searchText by viewModel.searchText.collectAsState()
    
    OutlinedTextField(
        value = searchText,
        onValueChange = viewModel::onSearchTextChanged,
        label = { Text("Поиск") }
    )
}

4. Стилизованные тематические компоненты

Компоненты, использующие общую Design System:

// Общая тема в commonMain
object AppTheme {
    val colors = AppColors(
        primary = Color(0xFF6200EE),
        surface = Color(0xFFFFFFFF)
    )
    
    val typography = AppTypography(
        h1 = TextStyle(fontSize = 24.sp, fontWeight = FontWeight.Bold)
    )
}

@Composable
fun ThemedCard(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
    Card(
        modifier = modifier,
        backgroundColor = AppTheme.colors.surface,
        elevation = 4.dp
    ) {
        content()
    }
}

Практические рекомендации по организации

Структура модулей:

shared/
├── commonMain/
│   ├── ui/           # Общие компоненты
│   ├── theme/        # Общая тема
│   └── di/           # Общая DI
├── androidMain/      # Android-специфичные реализации
└── desktopMain/      # Desktop-специфичные реализации

Что НЕ стоит обобщать:

  • Нативные контролы, специфичные для платформ (например, BottomSheet на Android может отличаться от Desktop)
  • Компоненты с платформенно-зависимыми жестами (долгое нажатие, масштабирование)
  • Элементы, требующие платформенных API (камера, GPS, файловая система)

Паттерны для работы с платформенными отличиями:

// Использование expect/actual для платформенных реализаций
expect class PlatformIcon

@Composable
expect fun PlatformSpecificComponent(
    modifier: Modifier = Modifier
)

// В Android-модуле
actual class PlatformIcon(context: Context) {
    // Android-специфичная реализация
}

@Composable
actual fun PlatformSpecificComponent(modifier: Modifier) {
    // Android-версия компонента
}

Преимущества общего подхода:

  1. Единая кодовая база — сокращение дублирования кода на 70-80%
  2. Согласованный UX — идентичное поведение на всех платформах
  3. Ускорение разработки — изменения применяются сразу везде
  4. Упрощённое тестирование — общие UI-тесты для всех платформ

Ограничения и решения:

  • Различия в input — используйте абстракции для обработки ввода
  • Разные гайдлайны — создавайте адаптивные компоненты с модификаторами
  • Производительность — тестируйте на целевых платформах

В качестве инструментов рекомендую: Compose Multiplatform для UI, MVIKotlin/ Decompose для архитектуры, Koin или Kodein-DI для dependency injection. Начните с простых stateless-компонентов, постепенно переходя к сложным stateful-виджетам, всегда проверяя рендеринг на каждой целевой платформе.

Какие UI-компоненты можно сделать общими для Android и Desktop в KMP проекте | PrepBro