The Icon component displays vector icons, image bitmaps, and custom painters. It provides automatic tinting and integrates seamlessly with Lumo UI’s theming system.
Usage
import com.nomanr.lumo.ui.components.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
// Vector icon
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = "Favorite"
)
// Bitmap icon
Icon(
bitmap = myBitmap,
contentDescription = "Custom icon"
)
// Custom painter
Icon(
painter = painterResource("icon.png"),
contentDescription = "Icon"
)
Vector Icons
The most common way to use icons with Material Icons:
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
// Filled icons
Icon(
imageVector = Icons.Filled.Home,
contentDescription = "Home"
)
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = "Settings"
)
// Outlined icons
Icon(
imageVector = Icons.Outlined.Person,
contentDescription = "Profile"
)
Bitmap Icons
Display icons from bitmap resources:
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.res.imageResource
val bitmap = ImageBitmap.imageResource("my_icon.png")
Icon(
bitmap = bitmap,
contentDescription = "Custom icon"
)
Custom Painter Icons
Use any painter implementation:
import androidx.compose.ui.res.painterResource
Icon(
painter = painterResource("icon.xml"),
contentDescription = "Vector drawable"
)
Tinting
Theme Color Tinting
Icons automatically use the current content color:
// Uses LocalContentColor by default
Icon(
imageVector = Icons.Default.Star,
contentDescription = "Star"
)
// Custom tint
Icon(
imageVector = Icons.Default.Star,
contentDescription = "Star",
tint = AppTheme.colors.primary
)
No Tinting
Display original colors:
import androidx.compose.ui.graphics.Color
Icon(
imageVector = colorfulIcon,
contentDescription = "Colorful icon",
tint = Color.Unspecified // Preserves original colors
)
Conditional Tinting
val isSelected = remember { mutableStateOf(false) }
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = "Favorite",
tint = if (isSelected.value) {
Color.Red
} else {
AppTheme.colors.onSurface
},
modifier = Modifier.clickable {
isSelected.value = !isSelected.value
}
)
Sizing
Default Size
Icons default to 24.dp if no intrinsic size is available:
// Default 24.dp
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu"
)
Custom Sizes
import androidx.compose.foundation.layout.size
// Small icon
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Check",
modifier = Modifier.size(16.dp)
)
// Large icon
Icon(
imageVector = Icons.Default.Image,
contentDescription = "Image",
modifier = Modifier.size(48.dp)
)
Responsive Sizing
// Fill available space
Icon(
imageVector = Icons.Default.Cloud,
contentDescription = "Cloud",
modifier = Modifier.fillMaxSize()
)
// Percentage of parent
Icon(
imageVector = Icons.Default.Download,
contentDescription = "Download",
modifier = Modifier.fillMaxSize(0.5f)
)
Parameters
Icon (ImageVector)
The vector image to display
Description for accessibility. Use null if the icon is purely decorative
modifier
Modifier
default:"Modifier"
Modifier for the icon
tint
Color
default:"LocalContentColor.current"
Tint color to apply to the icon
Icon (ImageBitmap)
The bitmap image to display
Description for accessibility
modifier
Modifier
default:"Modifier"
Modifier for the icon
tint
Color
default:"LocalContentColor.current"
Tint color to apply to the icon
Icon (Painter)
The painter to use for drawing the icon
Description for accessibility
modifier
Modifier
default:"Modifier"
Modifier for the icon
tint
Color
default:"LocalContentColor.current"
Tint color to apply to the icon
Common Use Cases
Button(
onClick = { /* Handle click */ },
variant = ButtonVariant.Primary
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(Modifier.width(8.dp))
Text("Add Item")
}
IconButton(
onClick = { /* Handle click */ },
variant = IconButtonVariant.Primary
) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete"
)
}
Navigation Icons
NavigationBarItem(
icon = {
Icon(
imageVector = if (selected) {
Icons.Filled.Home
} else {
Icons.Outlined.Home
},
contentDescription = "Home"
)
},
label = { Text("Home") },
selected = selected,
onClick = { /* Navigate */ }
)
Leading/Trailing Icons in Text Fields
TextField(
value = searchQuery,
onValueChange = { searchQuery = it },
leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = "Search"
)
},
trailingIcon = {
if (searchQuery.isNotEmpty()) {
IconButton(onClick = { searchQuery = "" }) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = "Clear"
)
}
}
}
)
Status Icons
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Icon(
imageVector = when (status) {
Status.Success -> Icons.Default.CheckCircle
Status.Warning -> Icons.Default.Warning
Status.Error -> Icons.Default.Error
Status.Info -> Icons.Default.Info
},
contentDescription = null,
tint = when (status) {
Status.Success -> Color.Green
Status.Warning -> Color.Yellow
Status.Error -> Color.Red
Status.Info -> Color.Blue
}
)
Text(statusMessage)
}
Styling
With Background
Box(
modifier = Modifier
.size(48.dp)
.background(
color = AppTheme.colors.primary,
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.Person,
contentDescription = "Profile",
tint = AppTheme.colors.onPrimary,
modifier = Modifier.size(24.dp)
)
}
With Border
Box(
modifier = Modifier
.size(48.dp)
.border(
width = 2.dp,
color = AppTheme.colors.primary,
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Add",
tint = AppTheme.colors.primary
)
}
Defaults
- Default Size: 24.dp (when painter has no intrinsic size)
- Default Tint:
LocalContentColor.current
- Content Scale: Fit (scales to fill while maintaining aspect ratio)
Accessibility
With Content Description
Always provide descriptions for interactive icons:
IconButton(onClick = { /* Delete */ }) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "Delete item" // Screen readers announce this
)
}
Decorative Icons
Use null for purely decorative icons:
Row {
Icon(
imageVector = Icons.Default.Star,
contentDescription = null // Decorative only
)
Text("Featured Item")
}
Best Practices
- Content Descriptions: Provide clear descriptions for interactive icons
- Decorative Icons: Use
null for contentDescription when icon is decorative
- Consistent Sizing: Use standard sizes (16dp, 24dp, 48dp) for consistency
- Color Contrast: Ensure icons have sufficient contrast with backgrounds
- Touch Targets: For interactive icons, ensure minimum 48dp touch target
- Loading: Show placeholder or shimmer while loading bitmap icons
- Theme Integration: Use theme colors for consistent appearance
Source Reference
See the full implementation in Icon.kt:27-39 (ImageVector), Icon.kt:42-55 (ImageBitmap), and Icon.kt:58-81 (Painter).