Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Design Android app UI/UX following Material Design 3 guidelines with Jetpack Compose layout patterns.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
SKILL.md
1---2name: mobile-android-design3description: 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.4---56# Android Mobile Design78Master Material Design 3 (Material You) and Jetpack Compose to build modern, adaptive Android applications that integrate seamlessly with the Android ecosystem.910## When to Use This Skill1112- Designing Android app interfaces following Material Design 313- Building Jetpack Compose UI and layouts14- Implementing Android navigation patterns (Navigation Compose)15- Creating adaptive layouts for phones, tablets, and foldables16- Using Material 3 theming with dynamic colors17- Building accessible Android interfaces18- Implementing Android-specific gestures and interactions19- Designing for different screen configurations2021## Core Concepts2223### 1. Material Design 3 Principles2425**Personalization**: Dynamic color adapts UI to user's wallpaper26**Accessibility**: Tonal palettes ensure sufficient color contrast27**Large Screens**: Responsive layouts for tablets and foldables2829**Material Components:**3031- Cards, Buttons, FABs, Chips32- Navigation (rail, drawer, bottom nav)33- Text fields, Dialogs, Sheets34- Lists, Menus, Progress indicators3536### 2. Jetpack Compose Layout System3738**Column and Row:**3940```kotlin41// Vertical arrangement with alignment42Column(43modifier = Modifier.padding(16.dp),44verticalArrangement = Arrangement.spacedBy(12.dp),45horizontalAlignment = Alignment.Start46) {47Text(48text = "Title",49style = MaterialTheme.typography.headlineSmall50)51Text(52text = "Subtitle",53style = MaterialTheme.typography.bodyMedium,54color = MaterialTheme.colorScheme.onSurfaceVariant55)56}5758// Horizontal arrangement with weight59Row(60modifier = Modifier.fillMaxWidth(),61horizontalArrangement = Arrangement.SpaceBetween,62verticalAlignment = Alignment.CenterVertically63) {64Icon(Icons.Default.Star, contentDescription = null)65Text("Featured")66Spacer(modifier = Modifier.weight(1f))67TextButton(onClick = {}) {68Text("View All")69}70}71```7273**Lazy Lists and Grids:**7475```kotlin76// Lazy column with sticky headers77LazyColumn {78items.groupBy { it.category }.forEach { (category, categoryItems) ->79stickyHeader {80Text(81text = category,82modifier = Modifier83.fillMaxWidth()84.background(MaterialTheme.colorScheme.surface)85.padding(16.dp),86style = MaterialTheme.typography.titleMedium87)88}89items(categoryItems) { item ->90ItemRow(item = item)91}92}93}9495// Adaptive grid96LazyVerticalGrid(97columns = GridCells.Adaptive(minSize = 150.dp),98contentPadding = PaddingValues(16.dp),99horizontalArrangement = Arrangement.spacedBy(12.dp),100verticalArrangement = Arrangement.spacedBy(12.dp)101) {102items(items) { item ->103ItemCard(item = item)104}105}106```107108### 3. Navigation Patterns109110**Bottom Navigation:**111112```kotlin113@Composable114fun MainScreen() {115val navController = rememberNavController()116117Scaffold(118bottomBar = {119NavigationBar {120val navBackStackEntry by navController.currentBackStackEntryAsState()121val currentDestination = navBackStackEntry?.destination122123NavigationDestination.entries.forEach { destination ->124NavigationBarItem(125icon = { Icon(destination.icon, contentDescription = null) },126label = { Text(destination.label) },127selected = currentDestination?.hierarchy?.any {128it.route == destination.route129} == true,130onClick = {131navController.navigate(destination.route) {132popUpTo(navController.graph.findStartDestination().id) {133saveState = true134}135launchSingleTop = true136restoreState = true137}138}139)140}141}142}143) { innerPadding ->144NavHost(145navController = navController,146startDestination = NavigationDestination.Home.route,147modifier = Modifier.padding(innerPadding)148) {149composable(NavigationDestination.Home.route) { HomeScreen() }150composable(NavigationDestination.Search.route) { SearchScreen() }151composable(NavigationDestination.Profile.route) { ProfileScreen() }152}153}154}155```156157**Navigation Drawer:**158159```kotlin160@Composable161fun DrawerNavigation() {162val drawerState = rememberDrawerState(DrawerValue.Closed)163val scope = rememberCoroutineScope()164165ModalNavigationDrawer(166drawerState = drawerState,167drawerContent = {168ModalDrawerSheet {169Spacer(Modifier.height(12.dp))170Text(171"App Name",172modifier = Modifier.padding(16.dp),173style = MaterialTheme.typography.titleLarge174)175HorizontalDivider()176177NavigationDrawerItem(178icon = { Icon(Icons.Default.Home, null) },179label = { Text("Home") },180selected = true,181onClick = { scope.launch { drawerState.close() } }182)183NavigationDrawerItem(184icon = { Icon(Icons.Default.Settings, null) },185label = { Text("Settings") },186selected = false,187onClick = { }188)189}190}191) {192Scaffold(193topBar = {194TopAppBar(195title = { Text("Home") },196navigationIcon = {197IconButton(onClick = { scope.launch { drawerState.open() } }) {198Icon(Icons.Default.Menu, contentDescription = "Menu")199}200}201)202}203) { innerPadding ->204Content(modifier = Modifier.padding(innerPadding))205}206}207}208```209210### 4. Material 3 Theming211212**Color Scheme:**213214```kotlin215// Dynamic color (Android 12+)216val dynamicColorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {217val context = LocalContext.current218if (darkTheme) dynamicDarkColorScheme(context)219else dynamicLightColorScheme(context)220} else {221if (darkTheme) DarkColorScheme else LightColorScheme222}223224// Custom color scheme225private val LightColorScheme = lightColorScheme(226primary = Color(0xFF6750A4),227onPrimary = Color.White,228primaryContainer = Color(0xFFEADDFF),229onPrimaryContainer = Color(0xFF21005D),230secondary = Color(0xFF625B71),231onSecondary = Color.White,232tertiary = Color(0xFF7D5260),233onTertiary = Color.White,234surface = Color(0xFFFFFBFE),235onSurface = Color(0xFF1C1B1F),236)237```238239**Typography:**240241```kotlin242val AppTypography = Typography(243displayLarge = TextStyle(244fontFamily = FontFamily.Default,245fontWeight = FontWeight.Normal,246fontSize = 57.sp,247lineHeight = 64.sp248),249headlineMedium = TextStyle(250fontFamily = FontFamily.Default,251fontWeight = FontWeight.Normal,252fontSize = 28.sp,253lineHeight = 36.sp254),255titleLarge = TextStyle(256fontFamily = FontFamily.Default,257fontWeight = FontWeight.Normal,258fontSize = 22.sp,259lineHeight = 28.sp260),261bodyLarge = TextStyle(262fontFamily = FontFamily.Default,263fontWeight = FontWeight.Normal,264fontSize = 16.sp,265lineHeight = 24.sp266),267labelMedium = TextStyle(268fontFamily = FontFamily.Default,269fontWeight = FontWeight.Medium,270fontSize = 12.sp,271lineHeight = 16.sp272)273)274```275276### 5. Component Examples277278**Cards:**279280```kotlin281@Composable282fun FeatureCard(283title: String,284description: String,285imageUrl: String,286onClick: () -> Unit287) {288Card(289onClick = onClick,290modifier = Modifier.fillMaxWidth(),291shape = RoundedCornerShape(16.dp),292colors = CardDefaults.cardColors(293containerColor = MaterialTheme.colorScheme.surfaceVariant294)295) {296Column {297AsyncImage(298model = imageUrl,299contentDescription = null,300modifier = Modifier301.fillMaxWidth()302.height(180.dp),303contentScale = ContentScale.Crop304)305Column(modifier = Modifier.padding(16.dp)) {306Text(307text = title,308style = MaterialTheme.typography.titleMedium309)310Spacer(modifier = Modifier.height(8.dp))311Text(312text = description,313style = MaterialTheme.typography.bodyMedium,314color = MaterialTheme.colorScheme.onSurfaceVariant315)316}317}318}319}320```321322**Buttons:**323324```kotlin325// Filled button (primary action)326Button(onClick = { }) {327Text("Continue")328}329330// Filled tonal button (secondary action)331FilledTonalButton(onClick = { }) {332Icon(Icons.Default.Add, null)333Spacer(Modifier.width(8.dp))334Text("Add Item")335}336337// Outlined button338OutlinedButton(onClick = { }) {339Text("Cancel")340}341342// Text button343TextButton(onClick = { }) {344Text("Learn More")345}346347// FAB348FloatingActionButton(349onClick = { },350containerColor = MaterialTheme.colorScheme.primaryContainer,351contentColor = MaterialTheme.colorScheme.onPrimaryContainer352) {353Icon(Icons.Default.Add, contentDescription = "Add")354}355```356357## Quick Start Component358359```kotlin360@Composable361fun ItemListCard(362item: Item,363onItemClick: () -> Unit,364modifier: Modifier = Modifier365) {366Card(367onClick = onItemClick,368modifier = modifier.fillMaxWidth(),369shape = RoundedCornerShape(12.dp)370) {371Row(372modifier = Modifier373.padding(16.dp)374.fillMaxWidth(),375verticalAlignment = Alignment.CenterVertically376) {377Box(378modifier = Modifier379.size(48.dp)380.clip(CircleShape)381.background(MaterialTheme.colorScheme.primaryContainer),382contentAlignment = Alignment.Center383) {384Icon(385imageVector = Icons.Default.Star,386contentDescription = null,387tint = MaterialTheme.colorScheme.onPrimaryContainer388)389}390391Spacer(modifier = Modifier.width(16.dp))392393Column(modifier = Modifier.weight(1f)) {394Text(395text = item.title,396style = MaterialTheme.typography.titleMedium397)398Text(399text = item.subtitle,400style = MaterialTheme.typography.bodyMedium,401color = MaterialTheme.colorScheme.onSurfaceVariant402)403}404405Icon(406imageVector = Icons.Default.ChevronRight,407contentDescription = null,408tint = MaterialTheme.colorScheme.onSurfaceVariant409)410}411}412}413```414415## Best Practices4164171. **Use Material Theme**: Access colors via `MaterialTheme.colorScheme` for automatic dark mode support4182. **Support Dynamic Color**: Enable dynamic color on Android 12+ for personalization4193. **Adaptive Layouts**: Use `WindowSizeClass` for responsive designs4204. **Content Descriptions**: Add `contentDescription` to all interactive elements4215. **Touch Targets**: Minimum 48dp touch targets for accessibility4226. **State Hoisting**: Hoist state to make components reusable and testable4237. **Remember Properly**: Use `remember` and `rememberSaveable` appropriately4248. **Preview Annotations**: Add `@Preview` with different configurations425426## Common Issues427428- **Recomposition Issues**: Avoid passing unstable lambdas; use `remember`429- **State Loss**: Use `rememberSaveable` for configuration changes430- **Performance**: Use `LazyColumn` instead of `Column` for long lists431- **Theme Leaks**: Ensure `MaterialTheme` wraps all composables432- **Navigation Crashes**: Handle back press and deep links properly433- **Memory Leaks**: Cancel coroutines in `DisposableEffect`434