ehmo/platform-design-skillsMIT4 files

Android Design Guidelines

Material Design 3 and Android platform guidelines. Use when building Android apps with Jetpack Compose or XML layouts, implementing Material You, navigation, or accessibility. Triggers on tasks involving Android UI, Compose components, dynamic color, or Material Design compliance.

Specification
Skill ID
ehmo/platform-design-skills/android-design-guidelines
Publisher
ehmo
Repository
platform-design-skills
Installs
0
Files
4
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

ehmo/platform-design-skills/android-design-guidelinesInstalls these files
  • AGENTS.md
  • SKILL.md
  • metadata.json
  • rules/_sections.md

What this skill tells the agent

Android Platform Design Guidelines — Material Design 3

1. Material You & Theming [CRITICAL]

1.1 Dynamic Color

Enable dynamic color derived from the user's wallpaper. Dynamic color is the default on Android 12+ and should be the primary theming strategy.

// Compose: Dynamic color theme
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context)
            else dynamicLightColorScheme(context)
        }
        darkTheme -> darkColorScheme()
        else -> lightColorScheme()
    }
    MaterialTheme(
        colorScheme = colorScheme,
        typography = AppTypography,
        content = content
    )
}
<!-- XML: Dynamic color in themes.xml -->
<style name="Theme.App" parent="Theme.Material3.DayNight.NoActionBar">
    <item name="dynamicColorThemeOverlay">@style/ThemeOverlay.Material3.DynamicColors.DayNight</item>
</style>

Rules:

  • R1.1: Always provide a fallback static color scheme for devices below Android 12.
  • R1.2: Never hardcode color hex values in components. Always reference color roles from the theme.
  • R1.3: Test with at least 3 different wallpapers to verify dynamic color harmony.

1.2 Color Roles

Material 3 defines a structured set of color roles. Use them semantically, not aesthetically.

RoleUsageOn-Role
primaryKey actions, active states, FABonPrimary
primaryContainerLess prominent primary elementsonPrimaryContainer
secondarySupporting UI, filter chipsonSecondary
secondaryContainerNavigation bar active indicatoronSecondaryContainer
tertiaryAccent, contrast, complementaryonTertiary
tertiaryContainerInput fields, less prominent accentsonTertiaryContainer
surfaceBackgrounds, cards, sheetsonSurface
surfaceVariantDecorative elements, dividersonSurfaceVariant
errorError states, destructive actionsonError
errorContainerError backgroundsonErrorContainer
outlineBorders, dividers—
outlineVariantSubtle borders—
inverseSurfaceSnackbar backgroundinverseOnSurface
// Correct: semantic color roles
Text(
    text = "Error message",
    color = MaterialTheme.colorScheme.error
)
Surface(color = MaterialTheme.colorScheme.errorContainer) {
    Text(text = "Error detail", color = MaterialTheme.colorScheme.onErrorContainer)
}

// WRONG: hardcoded colors
Text(text = "Error", color = Color(0xFFB00020)) // Anti-pattern

Rules:

  • R1.4: Every foreground element must use the matching on color role for its background (e.g., onPrimary text on primary background).
  • R1.5: Use surface and its variants for backgrounds. Never use primary or secondary as large background areas.
  • R1.6: Use tertiary sparingly for accent and complementary contrast only.

1.3 Light and Dark Themes

Support both light and dark themes. Respect the system setting by default.

// Compose: Detect system theme
val darkTheme = isSystemInDarkTheme()

Rules:

  • R1.7: Always support both light and dark themes. Never ship light-only.
  • R1.8: Dark theme surfaces use elevation-based tonal mapping, not pure black (#000000). Use surface color roles which handle this automatically.
  • R1.9: Provide a manual theme override in app settings (System / Light / Dark).

1.4 Custom Color Seeds

When branding requires custom colors, provide a seed color and generate tonal palettes using Material Theme Builder.

// Custom color scheme with brand seed
private val BrandLightColorScheme = lightColorScheme(
    primary = Color(0xFF1B6D2F),
    onPrimary = Color(0xFFFFFFFF),
    primaryContainer = Color(0xFFA4F6A8),
    onPrimaryContainer = Color(0xFF002107),
    // ... generate full palette from seed
)

Rules:

  • R1.10: Generate tonal palettes from seed colors using Material Theme Builder. Never manually pick individual tones.
  • R1.11: When using custom colors, still support dynamic color as the default and use custom colors as fallback.

2. Navigation [CRITICAL]

2.1 Navigation Bar (Bottom)

The primary navigation pattern for phones with 3-5 top-level destinations.

// Compose: Navigation Bar
NavigationBar {
    items.forEachIndexed { index, item ->
        NavigationBarItem(
            icon = {
                Icon(
                    imageVector = if (selectedItem == index) item.filledIcon else item.outlinedIcon,
                    contentDescription = item.label
                )
            },
            label = { Text(item.label) },
            selected = selectedItem == index,
            onClick = { selectedItem = index }
        )
    }
}

Rules:

  • R2.1: Use Navigation Bar for 3-5 top-level destinations on compact screens. Never use for fewer than 3 or more than 5.
  • R2.2: Always show labels on navigation bar items. Icon-only navigation bars are not permitted.
  • R2.3: Use filled icons for the selected state and outlined icons for unselected states.
  • R2.4: The active indicator uses secondaryContainer color. Do not override this.

2.2 Navigation Rail

For medium and expanded screens (tablets, foldables, desktop).

// Compose: Navigation Rail for larger screens
NavigationRail(
    header = {
        FloatingActionButton(
            onClick = { /* primary action */ },
            containerColor = MaterialTheme.colorScheme.tertiaryContainer
        ) {
            Icon(Icons.Default.Add, contentDescription = "Create")
        }
    }
) {
    items.forEachIndexed { index, item ->
        NavigationRailItem(
            icon = { Icon(item.icon, contentDescription = item.label) },
            label = { Text(item.label) },
            selected = selectedItem == index,
            onClick = { selectedItem = index }
        )
    }
}

Rules:

  • R2.5: Use Navigation Rail on medium (600-839dp) and expanded (840dp+) window sizes. Pair it with Navigation Bar on compact.
  • R2.6: Optionally include a FAB in the rail header for the primary action.
  • R2.7: Labels are optional on the rail but recommended for clarity.

2.3 Navigation Drawer

For 5+ destinations or complex navigation hierarchies, typically on expanded screens.

// Compose: Permanent Navigation Drawer for large screens
PermanentNavigationDrawer(
    drawerContent = {
        PermanentDrawerSheet {
            Text("App Name", modifier = Modifier.padding(16.dp),
                 style = MaterialTheme.typography.titleMedium)
            HorizontalDivider()
            items.forEach { item ->
                NavigationDrawerItem(
                    label = { Text(item.label) },
                    selected = item == selectedItem,
                    onClick = { selectedItem = item },
                    icon = { Icon(item.icon, contentDescription = null) }
                )
            }
        }
    }
) {
    Scaffold { /* page content */ }
}

Rules:

  • R2.8: Use modal drawer on compact screens, permanent drawer on expanded screens.
  • R2.9: Group drawer items into sections with dividers and section headers.

2.4 Predictive Back Gesture

Android 13+ supports predictive back with an animation preview.

// Compose: Predictive back with BackHandler (androidx.activity.compose)
BackHandler(enabled = true) {
    // Called when back is confirmed; navigate back in your nav controller
    navController.popBackStack()
}
// Compose: Predictive back progress animation using predictiveBackHandler modifier
// (androidx.activity:activity-compose 1.8+)
Modifier.predictiveBackHandler(enabled = true) { progress ->

Use this skill in a project

Open any RiverX project, search the Skills panel for ehmo/platform-design-skills/android-design-guidelines, and install it in one click.

Use this skill