Agent Skills
Discover and share powerful Agent Skills for AI assistants
mobile-android-design - Agent Skill - Agent Skills
Home/ Skills / mobile-android-design Master Material Design 3 and Jetpack Compose patterns for building native Android apps. Use when designing Android interfaces, implementing Compose UI, or following Google's Material Design guidelines.
Use the skills CLI to install this skill with one command. Auto-detects all installed AI assistants.
Method 1 - skills CLI
npx skills i wshobson/agents/plugins/ui-design/skills/mobile-android-design CopyMethod 2 - openskills (supports sync & update)
npx openskills install wshobson/agents CopyAuto-detects Claude Code, Cursor, Codex CLI, Gemini CLI, and more. One install, works everywhere.
Installation Path
Download and extract to one of the following locations:
Claude Code Cursor OpenCode Gemini CLI Codex CLI
~/.claude/skills/mobile-android-design/ Back No setup needed. Let our cloud agents run this skill for you.
Select Model
Claude Haiku 4.5 $0.10 Claude Sonnet 4.5 $0.20 Claude Opus 4.5 $0.50 Claude Sonnet 4.5 $0.20 /task
Best for coding tasks
Try NowEnvironment setup included
Android Mobile Design
Master Material Design 3 (Material You) and Jetpack Compose to build modern, adaptive Android applications that integrate seamlessly with the Android ecosystem.
When to Use This Skill
Designing Android app interfaces following Material Design 3
Building Jetpack Compose UI and layouts
Implementing Android navigation patterns (Navigation Compose)
Creating adaptive layouts for phones, tablets, and foldables
Using Material 3 theming with dynamic colors
Building accessible Android interfaces
Implementing Android-specific gestures and interactions
Designing for different screen configurations
Core Concepts
1. Material Design 3 Principles
Personalization : Dynamic color adapts UI to user's wallpaper
Accessibility : Tonal palettes ensure sufficient color contrast
Large Screens : Responsive layouts for tablets and foldables
Material Components:
Cards, Buttons, FABs, Chips
Navigation (rail, drawer, bottom nav)
Text fields, Dialogs, Sheets
Lists, Menus, Progress indicators
2. Jetpack Compose Layout System
Column and Row:
// Vertical arrangement with alignment
Column (
modifier = Modifier. padding ( 16 .dp),
verticalArrangement = Arrangement. spacedBy ( 12 .dp),
horizontalAlignment = Alignment.Start
) {
Text (
text = "Title"
Lazy Lists and Grids:
// Lazy column with sticky headers
LazyColumn {
items. groupBy { it.category }. forEach { (category, categoryItems) ->
stickyHeader {
Text (
text = category,
modifier = Modifier
. fillMaxWidth ()
.
3. Navigation Patterns
Bottom Navigation:
@Composable
fun MainScreen () {
val navController = rememberNavController ()
Scaffold (
bottomBar = {
Navigation Drawer:
@Composable
fun DrawerNavigation () {
val drawerState = rememberDrawerState (DrawerValue.Closed)
val scope = rememberCoroutineScope ()
ModalNavigationDrawer
4. Material 3 Theming
Color Scheme:
// Dynamic color (Android 12+)
val dynamicColorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme (context)
else dynamicLightColorScheme (context)
} else {
if (darkTheme) DarkColorScheme else LightColorScheme
Typography:
val AppTypography = Typography (
displayLarge = TextStyle (
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 57 .sp,
lineHeight = 64 .sp
),
headlineMedium
5. Component Examples
Cards:
@Composable
fun FeatureCard (
title: String ,
description: String ,
imageUrl: String ,
onClick: () -> Unit
) {
Card (
onClick
Buttons:
// Filled button (primary action)
Button (onClick = { }) {
Text ( "Continue" )
}
// Filled tonal button (secondary action)
FilledTonalButton (onClick = { }) {
Icon (Icons.Default.Add, null )
Spacer (Modifier. width ( 8 .dp))
Text (
Quick Start Component
@Composable
fun ItemListCard (
item: Item ,
onItemClick: () -> Unit,
modifier: Modifier = Modifier
) {
Best Practices
Use Material Theme : Access colors via MaterialTheme.colorScheme for automatic dark mode support
Support Dynamic Color : Enable dynamic color on Android 12+ for personalization
Adaptive Layouts : Use WindowSizeClass for responsive designs
Content Descriptions : Add contentDescription to all interactive elements
Touch Targets : Minimum 48dp touch targets for accessibility
State Hoisting : Hoist state to make components reusable and testable
Remember Properly : Use remember and rememberSaveable appropriately
Preview Annotations : Add @Preview with different configurations
Common Issues
Recomposition Issues : Avoid passing unstable lambdas; use remember
State Loss : Use rememberSaveable for configuration changes
Performance : Use LazyColumn instead of Column for long lists
Theme Leaks : Ensure MaterialTheme wraps all composables
Navigation Crashes : Handle back press and deep links properly
Memory Leaks : Cancel coroutines in DisposableEffect
Resources
,
style = MaterialTheme.typography.headlineSmall
)
Text (
text = "Subtitle" ,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
// Horizontal arrangement with weight
Row (
modifier = Modifier. fillMaxWidth (),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Icon (Icons.Default.Star, contentDescription = null )
Text ( "Featured" )
Spacer (modifier = Modifier. weight ( 1f ))
TextButton (onClick = {}) {
Text ( "View All" )
}
}
background
(MaterialTheme.colorScheme.surface)
. padding ( 16 .dp),
style = MaterialTheme.typography.titleMedium
)
}
items (categoryItems) { item ->
ItemRow (item = item)
}
}
}
// Adaptive grid
LazyVerticalGrid (
columns = GridCells. Adaptive (minSize = 150 .dp),
contentPadding = PaddingValues ( 16 .dp),
horizontalArrangement = Arrangement. spacedBy ( 12 .dp),
verticalArrangement = Arrangement. spacedBy ( 12 .dp)
) {
items (items) { item ->
ItemCard (item = item)
}
}
NavigationBar {
val navBackStackEntry by navController. currentBackStackEntryAsState ()
val currentDestination = navBackStackEntry?.destination
NavigationDestination.entries. forEach { destination ->
NavigationBarItem (
icon = { Icon (destination.icon, contentDescription = null ) },
label = { Text (destination.label) },
selected = currentDestination?.hierarchy?. any {
it.route == destination.route
} == true ,
onClick = {
navController. navigate (destination.route) {
popUpTo (navController.graph. findStartDestination ().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
) { innerPadding ->
NavHost (
navController = navController,
startDestination = NavigationDestination.Home.route,
modifier = Modifier. padding (innerPadding)
) {
composable (NavigationDestination.Home.route) { HomeScreen () }
composable (NavigationDestination.Search.route) { SearchScreen () }
composable (NavigationDestination.Profile.route) { ProfileScreen () }
}
}
}
(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet {
Spacer (Modifier. height ( 12 .dp))
Text (
"App Name" ,
modifier = Modifier. padding ( 16 .dp),
style = MaterialTheme.typography.titleLarge
)
HorizontalDivider ()
NavigationDrawerItem (
icon = { Icon (Icons.Default.Home, null ) },
label = { Text ( "Home" ) },
selected = true ,
onClick = { scope. launch { drawerState. close () } }
)
NavigationDrawerItem (
icon = { Icon (Icons.Default.Settings, null ) },
label = { Text ( "Settings" ) },
selected = false ,
onClick = { }
)
}
}
) {
Scaffold (
topBar = {
TopAppBar (
title = { Text ( "Home" ) },
navigationIcon = {
IconButton (onClick = { scope. launch { drawerState. open () } }) {
Icon (Icons.Default.Menu, contentDescription = "Menu" )
}
}
)
}
) { innerPadding ->
Content (modifier = Modifier. padding (innerPadding))
}
}
}
}
// Custom color scheme
private val LightColorScheme = lightColorScheme (
primary = Color ( 0xFF6750A4 ),
onPrimary = Color.White,
primaryContainer = Color ( 0xFFEADDFF ),
onPrimaryContainer = Color ( 0xFF21005D ),
secondary = Color ( 0xFF625B71 ),
onSecondary = Color.White,
tertiary = Color ( 0xFF7D5260 ),
onTertiary = Color.White,
surface = Color ( 0xFFFFFBFE ),
onSurface = Color ( 0xFF1C1B1F ),
)
=
TextStyle
(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 28 .sp,
lineHeight = 36 .sp
),
titleLarge = TextStyle (
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22 .sp,
lineHeight = 28 .sp
),
bodyLarge = TextStyle (
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16 .sp,
lineHeight = 24 .sp
),
labelMedium = TextStyle (
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 12 .sp,
lineHeight = 16 .sp
)
)
=
onClick,
modifier = Modifier. fillMaxWidth (),
shape = RoundedCornerShape ( 16 .dp),
colors = CardDefaults. cardColors (
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
Column {
AsyncImage (
model = imageUrl,
contentDescription = null ,
modifier = Modifier
. fillMaxWidth ()
. height ( 180 .dp),
contentScale = ContentScale.Crop
)
Column (modifier = Modifier. padding ( 16 .dp)) {
Text (
text = title,
style = MaterialTheme.typography.titleMedium
)
Spacer (modifier = Modifier. height ( 8 .dp))
Text (
text = description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
"Add Item"
)
}
// Outlined button
OutlinedButton (onClick = { }) {
Text ( "Cancel" )
}
// Text button
TextButton (onClick = { }) {
Text ( "Learn More" )
}
// FAB
FloatingActionButton (
onClick = { },
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
) {
Icon (Icons.Default.Add, contentDescription = "Add" )
}
Card (
onClick = onItemClick,
modifier = modifier. fillMaxWidth (),
shape = RoundedCornerShape ( 12 .dp)
) {
Row (
modifier = Modifier
. padding ( 16 .dp)
. fillMaxWidth (),
verticalAlignment = Alignment.CenterVertically
) {
Box (
modifier = Modifier
. size ( 48 .dp)
. clip (CircleShape)
. background (MaterialTheme.colorScheme.primaryContainer),
contentAlignment = Alignment.Center
) {
Icon (
imageVector = Icons.Default.Star,
contentDescription = null ,
tint = MaterialTheme.colorScheme.onPrimaryContainer
)
}
Spacer (modifier = Modifier. width ( 16 .dp))
Column (modifier = Modifier. weight ( 1f )) {
Text (
text = item.title,
style = MaterialTheme.typography.titleMedium
)
Text (
text = item.subtitle,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Icon (
imageVector = Icons.Default.ChevronRight,
contentDescription = null ,
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}