К основному содержанию
скилл CX Codex

android-jetpack-compose — скилл для Claude Code

Помогает агенту писать Android-интерфейсы на Jetpack Compose и выбирать паттерны состояния. Пригодится при работе с composable-функциями и ViewModel.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add TheBushidoCollective/han --skill android-jetpack-compose -a claude-code
npx skills add TheBushidoCollective/han --skill jetpack-compose -a claude-code
Открыть на GitHub

Что делает android-jetpack-compose

Скилл направляет работу над нативным Android UI на Jetpack Compose: состояние через remember, rememberSaveable, mutableStateOf и derivedStateOf, подъём состояния в родительский компонент, связка с ViewModel и StateFlow. Он также разбирает collectAsStateWithLifecycle для отображения состояния экрана.

В рекомендациях есть правила для composable-функций: параметр Modifier как первый необязательный аргумент, slot API для содержимого и стабильные ключи в списках. Учтены LaunchedEffect, DisposableEffect, SideEffect, Navigation Compose и темы Material 3. Для отфильтрованных списков предлагается derivedStateOf.

Скилл не вызывается пользователем напрямую, поэтому это повод формулировать Android-задачу явно. В его настройке доступны Read, Write, Edit, Bash, Grep и Glob.

Какие задачи решает

  • хранить состояние поля через rememberSaveable
  • поднимать состояние из дочернего composable
  • связать ViewModel со StateFlow экраном
  • добавить ключи элементам LazyColumn
  • выбрать эффект для загрузки или очистки ресурсов

Примеры запросов агенту

  • Перепиши UserScreen на Jetpack Compose со StateFlow из ViewModel.
  • Сделай NameInput без собственного состояния и подними значение в родительский компонент.
  • Добавь навигацию из home в detail/{itemId} через Navigation Compose.

Как установить android-jetpack-compose

1Через Skills CLI (Vercel)

npx skills add TheBushidoCollective/han --skill android-jetpack-compose -a claude-code
npx skills add TheBushidoCollective/han --skill jetpack-compose -a claude-code

2Вручную: положить файлы

~/.claude/skills/jetpack-compose/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/jetpack-compose/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора7

fastapi-async-patterns Скилл с готовыми шаблонами async-роутов, асинхронных баз данных, фоновых задач и WebSocket в FastAPI. Пригодится, когда API начинает тормозить на конкурентных запросах. CX Codex +1 953установок atomic-design-fundamentals Помогает разложить компоненты интерфейса по уровням Atomic Design: от токенов до страниц. Пригодится, когда в проекте уже сотня компонентов и непонятно, куда класть новый. CX Codex +1 766установок storybook-story-writing Пишет и правит истории Storybook для компонентов: формат CSF3, все состояния компонента, сборка без ошибок. Пригодится, когда сториз расползаются и ломают билд. CX Codex +1 673установок solid-principles Скилл подсказывает агенту применять пять принципов SOLID, когда он проектирует модули, функции и компоненты. Пригодится на этапе реализации, а не после ревью. CX Codex +1 554установок docker-compose-production Готовит конфигурации Docker Compose для продакшена: задаёт лимиты ресурсов, проверки healthcheck, ротацию логов, секреты и изоляцию сетей. CX Codex +1 484установок rails-hotwire Скилл для работы с Hotwire в Rails: Turbo Frames, Turbo Streams, трансляции и контроллеры Stimulus. Пригодится, когда нужно оживить страницы без тяжёлого JS. CX Codex +1 348установок

Похожие

android-jetpack-compose-cursorrules-prompt-file PatrickJS Правило для Cursor, которое задаёт агенту ориентиры по Android-разработке на Jetpack Compose: архитектура, состояние, тесты. ★ 41 011звёзд репо compose-graphics AThevon Скилл для продвинутой графики в Jetpack Compose: пружинная физика Material 3 Expressive, AGSL-шейдеры, Canvas и эффекты graphicsLayer. CX Codex +1 937установок migrate-xml-views-to-jetpack-compose Google LLC Ведёт миграцию одного XML-экрана Android в Jetpack Compose: от аудита до проверки и удаления устаревшей разметки. CX Codex +1 2 400установок wear-compose-m3 Google LLC Скилл ведёт агента по Wear OS Compose Material3: миграция с Material 2.5 и Horologist, готовые примеры компонентов, требования к сборке. CX Codex +1 1 200установок expo-ui-jetpack-compose официальный Expo Team Скилл подсказывает агенту, как писать нативные Android-интерфейсы через @expo/ui/jetpack-compose в приложении Expo. CX Codex GP ChatGPT 1установок compose-multiplatform-patterns affaan-m Скилл подсказывает паттерны Compose Multiplatform и Jetpack Compose для KMP-проектов: состояние, навигация, темы и UI под разные платформы. CX Codex +1 4 600установок

Рядом в теме «Мобильная разработка»

Всё по теме «Мобильная разработка» →

Вопросы о android-jetpack-compose

Как установить android-jetpack-compose в Claude Code?

Выполните по порядку npx skills add TheBushidoCollective/han --skill android-jetpack-compose -a claude-code, затем npx skills add TheBushidoCollective/han --skill jetpack-compose -a claude-code. Файл скилла находится в ~/.claude/skills/jetpack-compose/SKILL.md.

Что делает android-jetpack-compose?

Скилл даёт агенту паттерны разработки Android UI на Jetpack Compose. Он охватывает управление состоянием, ViewModel, эффекты, списки, навигацию и Material 3.

Какой способ состояния выбрать для Jetpack Compose?

remember сохраняет значение при рекомпозиции, а rememberSaveable переживает изменения конфигурации. Для вычисляемого состояния, которое зависит от других значений, используется derivedStateOf.

Исходный текст

SKILL.md · Apache-2.0
---
name: android-jetpack-compose
user-invocable: false
description: Use when building Android UIs with Jetpack Compose, managing state with remember/mutableStateOf, or implementing declarative UI patterns.
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
  - Grep
  - Glob
---

# Android - Jetpack Compose

Modern declarative UI toolkit for building native Android interfaces.

## Key Concepts

### State Management

Compose provides several ways to manage state:

- **remember**: Survives recomposition
- **rememberSaveable**: Survives configuration changes
- **mutableStateOf**: Creates observable state
- **derivedStateOf**: Computed state that updates when dependencies change

```kotlin
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Column {
        Text("Count: $count")
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}

// With saveable for configuration changes
@Composable
fun SearchField() {
    var query by rememberSaveable { mutableStateOf("") }

    TextField(
        value = query,
        onValueChange = { query = it },
        placeholder = { Text("Search...") }
    )
}
```

### State Hoisting

Lift state up to make composables stateless and reusable:

```kotlin
// Stateless composable
@Composable
fun NameInput(
    name: String,
    onNameChange: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    TextField(
        value = name,
        onValueChange = onNameChange,
        label = { Text("Name") },
        modifier = modifier
    )
}

// Stateful parent
@Composable
fun UserForm() {
    var name by remember { mutableStateOf("") }

    NameInput(
        name = name,
        onNameChange = { name = it }
    )
}
```

### ViewModel Integration

```kotlin
class UserViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UserUiState())
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    fun updateName(name: String) {
        _uiState.update { it.copy(name = name) }
    }

    fun saveUser() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true) }
            try {
                userRepository.save(_uiState.value.toUser())
                _uiState.update { it.copy(isLoading = false, isSaved = true) }
            } catch (e: Exception) {
                _uiState.update { it.copy(isLoading = false, error = e.message) }
            }
        }
    }
}

@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    UserContent(
        uiState = uiState,
        onNameChange = viewModel::updateName,
        onSave = viewModel::saveUser
    )
}
```

## Best Practices

### Composable Function Guidelines

```kotlin
// Use Modifier as first optional parameter
@Composable
fun CustomCard(
    title: String,
    modifier: Modifier = Modifier,
    onClick: () -> Unit = {}
) {
    Card(
        modifier = modifier.clickable(onClick = onClick)
    ) {
        Text(
            text = title,
            modifier = Modifier.padding(16.dp)
        )
    }
}

// Use slot APIs for flexible content
@Composable
fun CustomScaffold(
    topBar: @Composable () -> Unit = {},
    bottomBar: @Composable () -> Unit = {},
    content: @Composable (PaddingValues) -> Unit
) {
    Scaffold(
        topBar = topBar,
        bottomBar = bottomBar,
        content = content
    )
}
```

### Efficient Recomposition

```kotlin
// Use keys for list items
@Composable
fun UserList(users: List<User>) {
    LazyColumn {
        items(
            items = users,
            key = { it.id }  // Stable key for efficient updates
        ) { user ->
            UserItem(user)
        }
    }
}

// Use derivedStateOf for expensive computations
@Composable
fun FilteredList(items: List<Item>, query: String) {
    val filteredItems by remember(items, query) {
        derivedStateOf {
            items.filter { it.name.contains(query, ignoreCase = true) }
        }
    }

    LazyColumn {
        items(filteredItems) { item ->
            ItemRow(item)
        }
    }
}
```

### Side Effects

```kotlin
// LaunchedEffect for coroutine-based side effects
@Composable
fun UserProfile(userId: String, viewModel: UserViewModel) {
    LaunchedEffect(userId) {
        viewModel.loadUser(userId)
    }

    // UI content
}

// DisposableEffect for cleanup
@Composable
fun LifecycleAwareComponent(lifecycle: Lifecycle) {
    DisposableEffect(lifecycle) {
        val observer = LifecycleEventObserver { _, event ->
            // Handle lifecycle events
        }
        lifecycle.addObserver(observer)

        onDispose {
            lifecycle.removeObserver(observer)
        }
    }
}

// SideEffect for non-suspend side effects
@Composable
fun AnalyticsScreen(screenName: String) {
    SideEffect {
        analytics.logScreenView(screenName)
    }
}
```

## Common Patterns

### Navigation with Navigation Compose

```kotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        composable("home") {
            HomeScreen(
                onNavigateToDetail = { id ->
                    navController.navigate("detail/$id")
                }
            )
        }
        composable(
            route = "detail/{itemId}",
            arguments = listOf(navArgument("itemId") { type = NavType.StringType })
        ) { backStackEntry ->
            val itemId = backStackEntry.arguments?.getString("itemId")
            DetailScreen(itemId = itemId)
        }
    }
}
```

### Material 3 Theming

```kotlin
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        darkTheme -> darkColorScheme(
            primary = Purple80,
            secondary = PurpleGrey80,
            tertiary = Pink80
        )
        else -> lightColorScheme(
            primary = Purple40,
            secondary = PurpleGrey40,
            tertiary = Pink40
        )
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography,
        content = content
    )
}

// Using theme values
@Composable
fun ThemedCard() {
    Card(
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Text(
            text = "Themed content",
            style = MaterialTheme.typography.bodyLarge,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
    }
}
```

### Lists and Grids

```kotlin
@Composable
fun ProductGrid(products: List<Product>) {
    LazyVerticalGrid(
        columns = GridCells.Adaptive(minSize = 160.dp),
        contentPadding = PaddingValues(16.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        items(products, key = { it.id }) { product ->
            ProductCard(product)
        }
    }
}

// Sticky headers
@Composable
fun ContactList(contacts: Map<Char, List<Contact>>) {
    LazyColumn {
        contacts.forEach { (initial, contactsForInitial) ->
            stickyHeader {
                Text(
                    text = initial.toString(),
                    modifier = Modifier
                        .fillMaxWidth()
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(16.dp),
                    style = MaterialTheme.typography.titleMedium
                )
            }
            items(contactsForInitial) { contact ->
                ContactItem(contact)
            }
        }
    }
}
```

## Anti-Patterns

### Avoid Side Effects in Composition

Bad:

```kotlin
@Composable
fun BadExample(viewModel: ViewModel) {
    viewModel.loadData()  // Called on every recomposition!

    Text("Data loaded")
}
```

Good:

```kotlin
@Composable
fun GoodExample(viewModel: ViewModel) {
    LaunchedEffect(Unit) {
        viewModel.loadData()
    }

    Text("Data loaded")
}
```

### Don't Read State in Remember Block

Bad:

```kotlin
@Composable
fun BadCounter(initial: Int) {
    // Won't update when initial changes
    var count by remember { mutableStateOf(initial) }
}
```

Good:

```kotlin
@Composable
fun GoodCounter(initial: Int) {
    var count by remember(initial) { mutableStateOf(initial) }
}
```

### Avoid Heavy Computation During Composition

Bad:

```kotlin
@Composable
fun BadList(items: List<Item>) {
    // Runs on every recomposition
    val sorted = items.sortedBy { it.name }
    LazyColumn { /* ... */ }
}
```

Good:

```kotlin
@Composable
fun GoodList(items: List<Item>) {
    val sorted by remember(items) {
        derivedStateOf { items.sortedBy { it.name } }
    }
    LazyColumn { /* ... */ }
}
```

## Related Skills

- **android-architecture**: MVVM and clean architecture patterns
- **android-kotlin-coroutines**: Async operations in Compose

© TheBushidoCollective · Apache-2.0 · TheBushidoCollective/han

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой