783 lines
22 KiB
Markdown
783 lines
22 KiB
Markdown
---
|
||
name: android-native-dev
|
||
description: Android native application development and UI design guide. Covers Material Design 3, Kotlin/Compose development, project configuration, accessibility, and build troubleshooting. Read this before Android native application development.
|
||
license: MIT
|
||
metadata:
|
||
version: "1.0.0"
|
||
category: mobile
|
||
sources:
|
||
- Material Design 3 Guidelines (material.io)
|
||
- Android Developer Documentation (developer.android.com)
|
||
- Google Play Quality Guidelines
|
||
- WCAG Accessibility Guidelines
|
||
---
|
||
|
||
## 1. Project Scenario Assessment
|
||
|
||
Before starting development, assess the current project state:
|
||
|
||
| Scenario | Characteristics | Approach |
|
||
|----------|-----------------|----------|
|
||
| **Empty Directory** | No files present | Full initialization required, including Gradle Wrapper |
|
||
| **Has Gradle Wrapper** | `gradlew` and `gradle/wrapper/` exist | Use `./gradlew` directly for builds |
|
||
| **Android Studio Project** | Complete project structure, may lack wrapper | Check wrapper, run `gradle wrapper` if needed |
|
||
| **Incomplete Project** | Partial files present | Check missing files, complete configuration |
|
||
|
||
**Key Principles**:
|
||
- Before writing business logic, ensure `./gradlew assembleDebug` succeeds
|
||
- If `gradle.properties` is missing, create it first and configure AndroidX
|
||
|
||
### 1.1 Required Files Checklist
|
||
|
||
```
|
||
MyApp/
|
||
├── gradle.properties # Configure AndroidX and other settings
|
||
├── settings.gradle.kts
|
||
├── build.gradle.kts # Root level
|
||
├── gradle/wrapper/
|
||
│ └── gradle-wrapper.properties
|
||
├── app/
|
||
│ ├── build.gradle.kts # Module level
|
||
│ └── src/main/
|
||
│ ├── AndroidManifest.xml
|
||
│ ├── java/com/example/myapp/
|
||
│ │ └── MainActivity.kt
|
||
│ └── res/
|
||
│ ├── values/
|
||
│ │ ├── strings.xml
|
||
│ │ ├── colors.xml
|
||
│ │ └── themes.xml
|
||
│ └── mipmap-*/ # App icons
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Project Configuration
|
||
|
||
### 2.1 gradle.properties
|
||
|
||
```properties
|
||
# Required configuration
|
||
android.useAndroidX=true
|
||
android.enableJetifier=true
|
||
|
||
# Build optimization
|
||
org.gradle.parallel=true
|
||
kotlin.code.style=official
|
||
|
||
# JVM memory settings (adjust based on project size)
|
||
# Small projects: 2048m, Medium: 4096m, Large: 8192m+
|
||
# org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
|
||
```
|
||
|
||
> **Note**: If you encounter `OutOfMemoryError` during build, increase `-Xmx` value. Large projects with many dependencies may require 8GB or more.
|
||
|
||
### 2.2 Dependency Declaration Standards
|
||
|
||
```kotlin
|
||
dependencies {
|
||
// Use BOM to manage Compose versions
|
||
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
|
||
implementation("androidx.compose.ui:ui")
|
||
implementation("androidx.compose.material3:material3")
|
||
|
||
// Activity & ViewModel
|
||
implementation("androidx.activity:activity-compose:1.8.2")
|
||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
|
||
}
|
||
```
|
||
|
||
### 2.3 Build Variants & Product Flavors
|
||
|
||
Product Flavors allow you to create different versions of your app (e.g., free/paid, dev/staging/prod).
|
||
|
||
**Configuration in app/build.gradle.kts**:
|
||
|
||
```kotlin
|
||
android {
|
||
// Define flavor dimensions
|
||
flavorDimensions += "environment"
|
||
|
||
productFlavors {
|
||
create("dev") {
|
||
dimension = "environment"
|
||
applicationIdSuffix = ".dev"
|
||
versionNameSuffix = "-dev"
|
||
|
||
// Different config values per flavor
|
||
buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
|
||
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
|
||
|
||
// Different resources
|
||
resValue("string", "app_name", "MyApp Dev")
|
||
}
|
||
|
||
create("staging") {
|
||
dimension = "environment"
|
||
applicationIdSuffix = ".staging"
|
||
versionNameSuffix = "-staging"
|
||
|
||
buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
|
||
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
|
||
resValue("string", "app_name", "MyApp Staging")
|
||
}
|
||
|
||
create("prod") {
|
||
dimension = "environment"
|
||
// No suffix for production
|
||
|
||
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
|
||
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
|
||
resValue("string", "app_name", "MyApp")
|
||
}
|
||
}
|
||
|
||
buildTypes {
|
||
debug {
|
||
isDebuggable = true
|
||
isMinifyEnabled = false
|
||
}
|
||
release {
|
||
isDebuggable = false
|
||
isMinifyEnabled = true
|
||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Build Variant Naming**: `{flavor}{BuildType}` → e.g., `devDebug`, `prodRelease`
|
||
|
||
**Gradle Build Commands**:
|
||
|
||
```bash
|
||
# List all available build variants
|
||
./gradlew tasks --group="build"
|
||
|
||
# Build specific variant (flavor + buildType)
|
||
./gradlew assembleDevDebug # Dev flavor, Debug build
|
||
./gradlew assembleStagingDebug # Staging flavor, Debug build
|
||
./gradlew assembleProdRelease # Prod flavor, Release build
|
||
|
||
# Build all variants of a specific flavor
|
||
./gradlew assembleDev # All Dev variants (debug + release)
|
||
./gradlew assembleProd # All Prod variants
|
||
|
||
# Build all variants of a specific build type
|
||
./gradlew assembleDebug # All flavors, Debug build
|
||
./gradlew assembleRelease # All flavors, Release build
|
||
|
||
# Install specific variant to device
|
||
./gradlew installDevDebug
|
||
./gradlew installProdRelease
|
||
|
||
# Build and install in one command
|
||
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity
|
||
```
|
||
|
||
**Access BuildConfig in Code**:
|
||
|
||
> **Note**: Starting from AGP 8.0, `BuildConfig` is no longer generated by default. You must explicitly enable it in your `build.gradle.kts`:
|
||
> ```kotlin
|
||
> android {
|
||
> buildFeatures {
|
||
> buildConfig = true
|
||
> }
|
||
> }
|
||
> ```
|
||
|
||
```kotlin
|
||
// Use build config values in your code
|
||
val apiUrl = BuildConfig.API_BASE_URL
|
||
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING
|
||
|
||
if (BuildConfig.DEBUG) {
|
||
// Debug-only code
|
||
}
|
||
```
|
||
|
||
**Flavor-Specific Source Sets**:
|
||
|
||
```
|
||
app/src/
|
||
├── main/ # Shared code for all flavors
|
||
├── dev/ # Dev-only code and resources
|
||
│ ├── java/
|
||
│ └── res/
|
||
├── staging/ # Staging-only code and resources
|
||
├── prod/ # Prod-only code and resources
|
||
├── debug/ # Debug build type code
|
||
└── release/ # Release build type code
|
||
```
|
||
|
||
**Multiple Flavor Dimensions** (e.g., environment + tier):
|
||
|
||
```kotlin
|
||
android {
|
||
flavorDimensions += listOf("environment", "tier")
|
||
|
||
productFlavors {
|
||
create("dev") { dimension = "environment" }
|
||
create("prod") { dimension = "environment" }
|
||
|
||
create("free") { dimension = "tier" }
|
||
create("paid") { dimension = "tier" }
|
||
}
|
||
}
|
||
// Results in: devFreeDebug, devPaidDebug, prodFreeRelease, etc.
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Kotlin Development Standards
|
||
|
||
### 3.1 Naming Conventions
|
||
|
||
| Type | Convention | Example |
|
||
|------|------------|---------|
|
||
| Class/Interface | PascalCase | `UserRepository`, `MainActivity` |
|
||
| Function/Variable | camelCase | `getUserName()`, `isLoading` |
|
||
| Constant | SCREAMING_SNAKE | `MAX_RETRY_COUNT` |
|
||
| Package | lowercase | `com.example.myapp` |
|
||
| Composable | PascalCase | `@Composable fun UserCard()` |
|
||
|
||
### 3.2 Code Standards (Important)
|
||
|
||
**Null Safety**:
|
||
```kotlin
|
||
// ❌ Avoid: Non-null assertion !! (may crash)
|
||
val name = user!!.name
|
||
|
||
// ✅ Recommended: Safe call + default value
|
||
val name = user?.name ?: "Unknown"
|
||
|
||
// ✅ Recommended: let handling
|
||
user?.let { processUser(it) }
|
||
```
|
||
|
||
**Exception Handling**:
|
||
```kotlin
|
||
// ❌ Avoid: Random try-catch in business layer swallowing exceptions
|
||
fun loadData() {
|
||
try {
|
||
val data = api.fetch()
|
||
} catch (e: Exception) {
|
||
// Swallowing exception, hard to debug
|
||
}
|
||
}
|
||
|
||
// ✅ Recommended: Let exceptions propagate, handle at appropriate layer
|
||
suspend fun loadData(): Result<Data> {
|
||
return try {
|
||
Result.success(api.fetch())
|
||
} catch (e: Exception) {
|
||
Result.failure(e) // Wrap and return, let caller decide handling
|
||
}
|
||
}
|
||
|
||
// ✅ Recommended: Unified handling in ViewModel
|
||
viewModelScope.launch {
|
||
runCatching { repository.loadData() }
|
||
.onSuccess { _uiState.value = UiState.Success(it) }
|
||
.onFailure { _uiState.value = UiState.Error(it.message) }
|
||
}
|
||
```
|
||
|
||
### 3.3 Threading & Coroutines (Critical)
|
||
|
||
**Thread Selection Principles**:
|
||
|
||
| Operation Type | Thread | Description |
|
||
|----------------|--------|-------------|
|
||
| UI Updates | `Dispatchers.Main` | Update View, State, LiveData |
|
||
| Network Requests | `Dispatchers.IO` | HTTP calls, API requests |
|
||
| File I/O | `Dispatchers.IO` | Local storage, database operations |
|
||
| Compute Intensive | `Dispatchers.Default` | JSON parsing, sorting, encryption |
|
||
|
||
**Correct Usage**:
|
||
```kotlin
|
||
// In ViewModel
|
||
viewModelScope.launch {
|
||
// Default Main thread, can update UI State
|
||
_uiState.value = UiState.Loading
|
||
|
||
// Switch to IO thread for network request
|
||
val result = withContext(Dispatchers.IO) {
|
||
repository.fetchData()
|
||
}
|
||
|
||
// Automatically returns to Main thread, update UI
|
||
_uiState.value = UiState.Success(result)
|
||
}
|
||
|
||
// In Repository (suspend functions should be main-safe)
|
||
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
|
||
api.getData()
|
||
}
|
||
```
|
||
|
||
**Common Mistakes**:
|
||
```kotlin
|
||
// ❌ Wrong: Updating UI on IO thread
|
||
viewModelScope.launch(Dispatchers.IO) {
|
||
val data = api.fetch()
|
||
_uiState.value = data // Crash or warning!
|
||
}
|
||
|
||
// ❌ Wrong: Executing time-consuming operation on Main thread
|
||
viewModelScope.launch {
|
||
val data = api.fetch() // Blocking main thread! ANR
|
||
}
|
||
|
||
// ✅ Correct: Fetch on IO, update on Main
|
||
viewModelScope.launch {
|
||
val data = withContext(Dispatchers.IO) { api.fetch() }
|
||
_uiState.value = data
|
||
}
|
||
```
|
||
|
||
### 3.4 Visibility Rules
|
||
|
||
```kotlin
|
||
// Default is public, declare explicitly when needed
|
||
class UserRepository { // public
|
||
private val cache = mutableMapOf<String, User>() // Visible only within class
|
||
internal fun clearCache() {} // Visible only within module
|
||
}
|
||
|
||
// data class properties are public by default, be careful when used across modules
|
||
data class User(
|
||
val id: String, // public
|
||
val name: String
|
||
)
|
||
```
|
||
|
||
### 3.5 Common Syntax Pitfalls
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Accessing uninitialized lateinit
|
||
class MyViewModel : ViewModel() {
|
||
lateinit var data: String
|
||
fun process() = data.length // May crash
|
||
}
|
||
|
||
// ✅ Correct: Use nullable or default value
|
||
class MyViewModel : ViewModel() {
|
||
var data: String? = null
|
||
fun process() = data?.length ?: 0
|
||
}
|
||
|
||
// ❌ Wrong: Using return in lambda
|
||
list.forEach { item ->
|
||
if (item.isEmpty()) return // Returns from outer function!
|
||
}
|
||
|
||
// ✅ Correct: Use return@forEach
|
||
list.forEach { item ->
|
||
if (item.isEmpty()) return@forEach
|
||
}
|
||
```
|
||
|
||
### 3.6 Server Response Data Class Fields Must Be Nullable
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Fields declared as non-null (server may not return them)
|
||
data class UserResponse(
|
||
val id: String = "",
|
||
val name: String = "",
|
||
val avatar: String = ""
|
||
)
|
||
|
||
// ✅ Correct: All fields declared as nullable
|
||
data class UserResponse(
|
||
@SerializedName("id")
|
||
val id: String? = null,
|
||
@SerializedName("name")
|
||
val name: String? = null,
|
||
@SerializedName("avatar")
|
||
val avatar: String? = null
|
||
)
|
||
```
|
||
|
||
### 3.7 Lifecycle Resource Management
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Only adding Observer, not removing
|
||
class MyView : View {
|
||
override fun onAttachedToWindow() {
|
||
super.onAttachedToWindow()
|
||
activity?.lifecycle?.addObserver(this)
|
||
}
|
||
// Memory leak!
|
||
}
|
||
|
||
// ✅ Correct: Paired add and remove
|
||
class MyView : View {
|
||
override fun onAttachedToWindow() {
|
||
super.onAttachedToWindow()
|
||
activity?.lifecycle?.addObserver(this)
|
||
}
|
||
|
||
override fun onDetachedFromWindow() {
|
||
activity?.lifecycle?.removeObserver(this)
|
||
super.onDetachedFromWindow()
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.8 Logging Level Usage
|
||
|
||
```kotlin
|
||
import android.util.Log
|
||
|
||
// Info: Key checkpoints in normal flow
|
||
Log.i(TAG, "loadData: started, userId = $userId")
|
||
|
||
// Warning: Abnormal but recoverable situations
|
||
Log.w(TAG, "loadData: cache miss, fallback to network")
|
||
|
||
// Error: Failure/error situations
|
||
Log.e(TAG, "loadData failed: ${error.message}")
|
||
```
|
||
|
||
| Level | Use Case |
|
||
|-------|----------|
|
||
| `i` (Info) | Normal flow, method entry, key parameters |
|
||
| `w` (Warning) | Recoverable exceptions, fallback handling, null returns |
|
||
| `e` (Error) | Request failures, caught exceptions, unrecoverable errors |
|
||
|
||
---
|
||
|
||
## 4. Jetpack Compose Standards
|
||
|
||
### 4.1 @Composable Context Rules
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Calling Composable from non-Composable function
|
||
fun showError(message: String) {
|
||
Text(message) // Compile error!
|
||
}
|
||
|
||
// ✅ Correct: Mark as @Composable
|
||
@Composable
|
||
fun ErrorMessage(message: String) {
|
||
Text(message)
|
||
}
|
||
|
||
// ❌ Wrong: Using suspend outside LaunchedEffect
|
||
@Composable
|
||
fun MyScreen() {
|
||
val data = fetchData() // Error!
|
||
}
|
||
|
||
// ✅ Correct: Use LaunchedEffect
|
||
@Composable
|
||
fun MyScreen() {
|
||
var data by remember { mutableStateOf<Data?>(null) }
|
||
LaunchedEffect(Unit) {
|
||
data = fetchData()
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 State Management
|
||
|
||
```kotlin
|
||
// Basic State
|
||
var count by remember { mutableStateOf(0) }
|
||
|
||
// Derived State (avoid redundant computation)
|
||
val isEven by remember { derivedStateOf { count % 2 == 0 } }
|
||
|
||
// Persist across recomposition (e.g., scroll position)
|
||
val scrollState = rememberScrollState()
|
||
|
||
// State in ViewModel
|
||
class MyViewModel : ViewModel() {
|
||
private val _uiState = MutableStateFlow(UiState())
|
||
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
||
}
|
||
```
|
||
|
||
### 4.3 Common Compose Mistakes
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Creating objects in Composable (created on every recomposition)
|
||
@Composable
|
||
fun MyScreen() {
|
||
val viewModel = MyViewModel() // Wrong!
|
||
}
|
||
|
||
// ✅ Correct: Use viewModel() or remember
|
||
@Composable
|
||
fun MyScreen(viewModel: MyViewModel = viewModel()) {
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Resources & Icons
|
||
|
||
### 5.1 App Icon Requirements
|
||
|
||
Must provide multi-resolution icons:
|
||
|
||
| Directory | Size | Purpose |
|
||
|-----------|------|---------|
|
||
| mipmap-mdpi | 48x48 | Baseline |
|
||
| mipmap-hdpi | 72x72 | 1.5x |
|
||
| mipmap-xhdpi | 96x96 | 2x |
|
||
| mipmap-xxhdpi | 144x144 | 3x |
|
||
| mipmap-xxxhdpi | 192x192 | 4x |
|
||
|
||
Recommended: Use Adaptive Icon (Android 8+):
|
||
|
||
```xml
|
||
<!-- res/mipmap-anydpi-v26/ic_launcher.xml -->
|
||
<adaptive-icon>
|
||
<background android:drawable="@color/ic_launcher_background"/>
|
||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||
</adaptive-icon>
|
||
```
|
||
|
||
### 5.2 Resource Naming Conventions
|
||
|
||
| Type | Prefix | Example |
|
||
|------|--------|---------|
|
||
| Layout | layout_ | `layout_main.xml` |
|
||
| Image | ic_, img_, bg_ | `ic_user.png` |
|
||
| Color | color_ | `color_primary` |
|
||
| String | - | `app_name`, `btn_submit` |
|
||
|
||
### 5.3 Avoid Android Reserved Names (Important)
|
||
|
||
Variable names, resource IDs, colors, icons, and XML elements **must not** use Android reserved words or system resource names. Using reserved names causes build errors or resource conflicts.
|
||
|
||
**Common Reserved Names to Avoid**:
|
||
|
||
| Category | Reserved Names (Do NOT Use) |
|
||
|----------|----------------------------|
|
||
| Colors | `background`, `foreground`, `transparent`, `white`, `black` |
|
||
| Icons/Drawables | `icon`, `logo`, `image`, `drawable` |
|
||
| Views | `view`, `text`, `button`, `layout`, `container` |
|
||
| Attributes | `id`, `name`, `type`, `style`, `theme`, `color` |
|
||
| System | `app`, `android`, `content`, `data`, `action` |
|
||
|
||
**Examples**:
|
||
|
||
```xml
|
||
<!-- ❌ Wrong: Using reserved names -->
|
||
<color name="background">#FFFFFF</color>
|
||
<color name="icon">#000000</color>
|
||
|
||
<!-- ✅ Correct: Add prefix or specific naming -->
|
||
<color name="app_background">#FFFFFF</color>
|
||
<color name="icon_primary">#000000</color>
|
||
```
|
||
|
||
```kotlin
|
||
// ❌ Wrong: Variable names conflict with system
|
||
val icon = R.drawable.my_icon
|
||
val background = Color.White
|
||
|
||
// ✅ Correct: Use descriptive names
|
||
val appIcon = R.drawable.my_icon
|
||
val screenBackground = Color.White
|
||
```
|
||
|
||
```xml
|
||
<!-- ❌ Wrong: Drawable name conflicts -->
|
||
<ImageView android:src="@drawable/icon" />
|
||
|
||
<!-- ✅ Correct: Add prefix -->
|
||
<ImageView android:src="@drawable/ic_home" />
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Build Error Diagnosis & Fixes
|
||
|
||
### 6.1 Common Error Quick Reference
|
||
|
||
| Error Keyword | Cause | Fix |
|
||
|---------------|-------|-----|
|
||
| `Unresolved reference` | Missing import or undefined | Check imports, verify dependencies |
|
||
| `Type mismatch` | Type incompatibility | Check parameter types, add conversion |
|
||
| `Cannot access` | Visibility issue | Check public/private/internal |
|
||
| `@Composable invocations` | Composable context error | Ensure caller is also @Composable |
|
||
| `Duplicate class` | Dependency conflict | Use `./gradlew dependencies` to investigate |
|
||
| `AAPT: error` | Resource file error | Check XML syntax and resource references |
|
||
|
||
### 6.2 Fix Best Practices
|
||
|
||
1. **Read the complete error message first**: Locate file and line number
|
||
2. **Check recent changes**: Problems usually in latest modifications
|
||
3. **Clean Build**: `./gradlew clean assembleDebug`
|
||
4. **Check dependency versions**: Version conflicts are common causes
|
||
5. **Refresh dependencies if needed**: Clear cache and rebuild
|
||
|
||
### 6.3 Debugging Commands
|
||
|
||
```bash
|
||
# Clean and build
|
||
./gradlew clean assembleDebug
|
||
|
||
# View dependency tree (investigate conflicts)
|
||
./gradlew :app:dependencies
|
||
|
||
# View detailed errors
|
||
./gradlew assembleDebug --stacktrace
|
||
|
||
# Refresh dependencies
|
||
./gradlew --refresh-dependencies
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Material Design 3 Guidelines
|
||
|
||
Review Android UI files for compliance with Material Design 3 Guidelines and Android best practices.
|
||
|
||
### Design Philosophy
|
||
|
||
#### M3 Core Principles
|
||
|
||
| Principle | Description |
|
||
|-----------|-------------|
|
||
| **Personal** | Dynamic color based on user preferences and wallpaper |
|
||
| **Adaptive** | Responsive across all screen sizes and form factors |
|
||
| **Expressive** | Bold colors and typography with personality |
|
||
| **Accessible** | Inclusive design for all users |
|
||
|
||
#### M3 Expressive (Latest)
|
||
|
||
The latest evolution adds emotion-driven UX through:
|
||
- Vibrant, dynamic colors
|
||
- Intuitive motion physics
|
||
- Adaptive components
|
||
- Flexible typography
|
||
- Contrasting shapes (35 new shape options)
|
||
|
||
### App Style Selection
|
||
|
||
**Critical Decision**: Match visual style to app category and target audience.
|
||
|
||
| App Category | Visual Style | Key Characteristics |
|
||
|--------------|--------------|---------------------|
|
||
| Utility/Tool | Minimalist | Clean, efficient, neutral colors |
|
||
| Finance/Banking | Professional Trust | Conservative colors, security-focused |
|
||
| Health/Wellness | Calm & Natural | Soft colors, organic shapes |
|
||
| Kids (3-5) | Playful Simple | Bright colors, large targets (56dp+) |
|
||
| Kids (6-12) | Fun & Engaging | Vibrant, gamified feedback |
|
||
| Social/Entertainment | Expressive | Brand-driven, gesture-rich |
|
||
| Productivity | Clean & Focused | Minimal, high contrast |
|
||
| E-commerce | Conversion-focused | Clear CTAs, scannable |
|
||
|
||
See [Design Style Guide](references/design-style-guide.md) for detailed style profiles.
|
||
|
||
### Quick Reference: Key Specifications
|
||
|
||
#### Color Contrast Requirements
|
||
|
||
| Element | Minimum Ratio |
|
||
|---------|---------------|
|
||
| Body text | **4.5:1** |
|
||
| Large text (18sp+) | **3:1** |
|
||
| UI components | **3:1** |
|
||
|
||
#### Touch Targets
|
||
|
||
| Type | Size |
|
||
|------|------|
|
||
| Minimum | 48 × 48dp |
|
||
| Recommended (primary actions) | 56 × 56dp |
|
||
| Kids apps | 56dp+ |
|
||
| Spacing between targets | 8dp minimum |
|
||
|
||
#### 8dp Grid System
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| xs | 4dp | Icon padding |
|
||
| sm | 8dp | Tight spacing |
|
||
| md | 16dp | Default padding |
|
||
| lg | 24dp | Section spacing |
|
||
| xl | 32dp | Large gaps |
|
||
| xxl | 48dp | Screen margins |
|
||
|
||
#### Typography Scale (Summary)
|
||
|
||
| Category | Sizes |
|
||
|----------|-------|
|
||
| Display | 57sp, 45sp, 36sp |
|
||
| Headline | 32sp, 28sp, 24sp |
|
||
| Title | 22sp, 16sp, 14sp |
|
||
| Body | 16sp, 14sp, 12sp |
|
||
| Label | 14sp, 12sp, 11sp |
|
||
|
||
#### Animation Duration
|
||
|
||
| Type | Duration |
|
||
|------|----------|
|
||
| Micro (ripples) | 50-100ms |
|
||
| Short (simple) | 100-200ms |
|
||
| Medium (expand/collapse) | 200-300ms |
|
||
| Long (complex) | 300-500ms |
|
||
|
||
#### Component Dimensions
|
||
|
||
| Component | Height | Min Width |
|
||
|-----------|--------|-----------|
|
||
| Button | 40dp | 64dp |
|
||
| FAB | 56dp | 56dp |
|
||
| Text Field | 56dp | 280dp |
|
||
| App Bar | 64dp | - |
|
||
| Bottom Nav | 80dp | - |
|
||
|
||
### Anti-Patterns (Must Avoid)
|
||
|
||
#### UI Anti-Patterns
|
||
- More than 5 bottom navigation items
|
||
- Multiple FABs on same screen
|
||
- Touch targets smaller than 48dp
|
||
- Inconsistent spacing (non-8dp multiples)
|
||
- Missing dark theme support
|
||
- Text on colored backgrounds without contrast check
|
||
|
||
#### Performance Anti-Patterns
|
||
- Startup time > 2 seconds without progress indicator
|
||
- Frame rate < 60 FPS (> 16ms per frame)
|
||
- Crash rate > 1.09% (Google Play threshold)
|
||
- ANR rate > 0.47% (Google Play threshold)
|
||
|
||
#### Accessibility Anti-Patterns
|
||
- Missing contentDescription on interactive elements
|
||
- Element type in labels (e.g., "Save button" instead of "Save")
|
||
- Complex gestures in kids apps
|
||
- Text-only buttons for non-readers
|
||
|
||
### Review Checklist
|
||
|
||
- [ ] 8dp spacing grid compliance
|
||
- [ ] 48dp minimum touch targets
|
||
- [ ] Proper typography scale usage
|
||
- [ ] Color contrast compliance (4.5:1+ for text)
|
||
- [ ] Dark theme support
|
||
- [ ] contentDescription on all interactive elements
|
||
- [ ] Startup < 2 seconds or shows progress
|
||
- [ ] Visual style matches app category
|
||
|
||
### Design References
|
||
|
||
| Topic | Reference |
|
||
|-------|-----------|
|
||
| Colors, Typography, Spacing, Shapes | [Visual Design](references/visual-design.md) |
|
||
| Animation & Transitions | [Motion System](references/motion-system.md) |
|
||
| Accessibility Guidelines | [Accessibility](references/accessibility.md) |
|
||
| Large Screens & Foldables | [Adaptive Screens](references/adaptive-screens.md) |
|
||
| Android Vitals & Performance | [Performance & Stability](references/performance-stability.md) |
|
||
| Privacy & Security | [Privacy & Security](references/privacy-security.md) |
|
||
| Audio, Video, Notifications | [Functional Requirements](references/functional-requirements.md) |
|
||
| App Style by Category | [Design Style Guide](references/design-style-guide.md) |
|