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.
references/details.md
1# mobile-android-design — detailed sections23## Core Concepts45### 1. Material Design 3 Principles67**Personalization**: Dynamic color adapts UI to user's wallpaper8**Accessibility**: Tonal palettes ensure sufficient color contrast9**Large Screens**: Responsive layouts for tablets and foldables1011**Material Components:**1213- Cards, Buttons, FABs, Chips14- Navigation (rail, drawer, bottom nav)15- Text fields, Dialogs, Sheets16- Lists, Menus, Progress indicators1718### 2. Jetpack Compose Layout System1920**Column and Row:**2122```kotlin23// Vertical arrangement with alignment24Column(25modifier = Modifier.padding(16.dp),26verticalArrangement = Arrangement.spacedBy(12.dp),27horizontalAlignment = Alignment.Start28) {29Text(30text = "Title",31style = MaterialTheme.typography.headlineSmall32)33Text(34text = "Subtitle",35style = MaterialTheme.typography.bodyMedium,36color = MaterialTheme.colorScheme.onSurfaceVariant37)38}3940// Horizontal arrangement with weight41Row(42modifier = Modifier.fillMaxWidth(),43horizontalArrangement = Arrangement.SpaceBetween,44verticalAlignment = Alignment.CenterVertically45) {46Icon(Icons.Default.Star, contentDescription = null)47Text("Featured")48Spacer(modifier = Modifier.weight(1f))49TextButton(onClick = {}) {50Text("View All")51}52}53```5455**Lazy Lists and Grids:**5657```kotlin58// Lazy column with sticky headers59LazyColumn {60items.groupBy { it.category }.forEach { (category, categoryItems) ->61stickyHeader {62Text(63text = category,64modifier = Modifier65.fillMaxWidth()66.background(MaterialTheme.colorScheme.surface)67.padding(16.dp),68style = MaterialTheme.typography.titleMedium69)70}71items(categoryItems) { item ->72ItemRow(item = item)73}74}75}7677// Adaptive grid78LazyVerticalGrid(79columns = GridCells.Adaptive(minSize = 150.dp),80contentPadding = PaddingValues(16.dp),81horizontalArrangement = Arrangement.spacedBy(12.dp),82verticalArrangement = Arrangement.spacedBy(12.dp)83) {84items(items) { item ->85ItemCard(item = item)86}87}88```8990### 3. Navigation Patterns9192**Bottom Navigation:**9394```kotlin95@Composable96fun MainScreen() {97val navController = rememberNavController()9899Scaffold(100bottomBar = {101NavigationBar {102val navBackStackEntry by navController.currentBackStackEntryAsState()103val currentDestination = navBackStackEntry?.destination104105NavigationDestination.entries.forEach { destination ->106NavigationBarItem(107icon = { Icon(destination.icon, contentDescription = null) },108label = { Text(destination.label) },109selected = currentDestination?.hierarchy?.any {110it.route == destination.route111} == true,112onClick = {113navController.navigate(destination.route) {114popUpTo(navController.graph.findStartDestination().id) {115saveState = true116}117launchSingleTop = true118restoreState = true119}120}121)122}123}124}125) { innerPadding ->126NavHost(127navController = navController,128startDestination = NavigationDestination.Home.route,129modifier = Modifier.padding(innerPadding)130) {131composable(NavigationDestination.Home.route) { HomeScreen() }132composable(NavigationDestination.Search.route) { SearchScreen() }133composable(NavigationDestination.Profile.route) { ProfileScreen() }134}135}136}137```138139**Navigation Drawer:**140141```kotlin142@Composable143fun DrawerNavigation() {144val drawerState = rememberDrawerState(DrawerValue.Closed)145val scope = rememberCoroutineScope()146147ModalNavigationDrawer(148drawerState = drawerState,149drawerContent = {150ModalDrawerSheet {151Spacer(Modifier.height(12.dp))152Text(153"App Name",154modifier = Modifier.padding(16.dp),155style = MaterialTheme.typography.titleLarge156)157HorizontalDivider()158159NavigationDrawerItem(160icon = { Icon(Icons.Default.Home, null) },161label = { Text("Home") },162selected = true,163onClick = { scope.launch { drawerState.close() } }164)165NavigationDrawerItem(166icon = { Icon(Icons.Default.Settings, null) },167label = { Text("Settings") },168selected = false,169onClick = { }170)171}172}173) {174Scaffold(175topBar = {176TopAppBar(177title = { Text("Home") },178navigationIcon = {179IconButton(onClick = { scope.launch { drawerState.open() } }) {180Icon(Icons.Default.Menu, contentDescription = "Menu")181}182}183)184}185) { innerPadding ->186Content(modifier = Modifier.padding(innerPadding))187}188}189}190```191192### 4. Material 3 Theming193194**Color Scheme:**195196```kotlin197// Dynamic color (Android 12+)198val dynamicColorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {199val context = LocalContext.current200if (darkTheme) dynamicDarkColorScheme(context)201else dynamicLightColorScheme(context)202} else {203if (darkTheme) DarkColorScheme else LightColorScheme204}205206// Custom color scheme207private val LightColorScheme = lightColorScheme(208primary = Color(0xFF6750A4),209onPrimary = Color.White,210primaryContainer = Color(0xFFEADDFF),211onPrimaryContainer = Color(0xFF21005D),212secondary = Color(0xFF625B71),213onSecondary = Color.White,214tertiary = Color(0xFF7D5260),215onTertiary = Color.White,216surface = Color(0xFFFFFBFE),217onSurface = Color(0xFF1C1B1F),218)219```220221**Typography:**222223```kotlin224val AppTypography = Typography(225displayLarge = TextStyle(226fontFamily = FontFamily.Default,227fontWeight = FontWeight.Normal,228fontSize = 57.sp,229lineHeight = 64.sp230),231headlineMedium = TextStyle(232fontFamily = FontFamily.Default,233fontWeight = FontWeight.Normal,234fontSize = 28.sp,235lineHeight = 36.sp236),237titleLarge = TextStyle(238fontFamily = FontFamily.Default,239fontWeight = FontWeight.Normal,240fontSize = 22.sp,241lineHeight = 28.sp242),243bodyLarge = TextStyle(244fontFamily = FontFamily.Default,245fontWeight = FontWeight.Normal,246fontSize = 16.sp,247lineHeight = 24.sp248),249labelMedium = TextStyle(250fontFamily = FontFamily.Default,251fontWeight = FontWeight.Medium,252fontSize = 12.sp,253lineHeight = 16.sp254)255)256```257258### 5. Component Examples259260**Cards:**261262```kotlin263@Composable264fun FeatureCard(265title: String,266description: String,267imageUrl: String,268onClick: () -> Unit269) {270Card(271onClick = onClick,272modifier = Modifier.fillMaxWidth(),273shape = RoundedCornerShape(16.dp),274colors = CardDefaults.cardColors(275containerColor = MaterialTheme.colorScheme.surfaceVariant276)277) {278Column {279AsyncImage(280model = imageUrl,281contentDescription = null,282modifier = Modifier283.fillMaxWidth()284.height(180.dp),285contentScale = ContentScale.Crop286)287Column(modifier = Modifier.padding(16.dp)) {288Text(289text = title,290style = MaterialTheme.typography.titleMedium291)292Spacer(modifier = Modifier.height(8.dp))293Text(294text = description,295style = MaterialTheme.typography.bodyMedium,296color = MaterialTheme.colorScheme.onSurfaceVariant297)298}299}300}301}302```303304**Buttons:**305306```kotlin307// Filled button (primary action)308Button(onClick = { }) {309Text("Continue")310}311312// Filled tonal button (secondary action)313FilledTonalButton(onClick = { }) {314Icon(Icons.Default.Add, null)315Spacer(Modifier.width(8.dp))316Text("Add Item")317}318319// Outlined button320OutlinedButton(onClick = { }) {321Text("Cancel")322}323324// Text button325TextButton(onClick = { }) {326Text("Learn More")327}328329// FAB330FloatingActionButton(331onClick = { },332containerColor = MaterialTheme.colorScheme.primaryContainer,333contentColor = MaterialTheme.colorScheme.onPrimaryContainer334) {335Icon(Icons.Default.Add, contentDescription = "Add")336}337```338