Jetpack Compose: Shaping Your UI with Clipping and Masking
Last updated Dec 24, 2024Compose is a modern toolkit for building native UI on Android. It simplifies and accelerates UI development with less code, powerful tools, and an intuitive Kotlin API. Here are some tips to help you create delightful UIs with Compose
How to Create Stacked Avatars in Jetpack Compose

Jetpack Compose is a modern toolkit for building user interfaces on Android, focusing on UI design through techniques such as clipping and masking. It utilizes shapes and paths to create visually appealing components, enhanced by various modifiers that allow developers to customize their applications. This framework is integral to Android and mobile development, facilitating the creation of intuitive user interfaces that improve the overall user experience. Developers leverage Kotlin programming to implement these features effectively
Embrace Composable Functions
Everything is a Composable: Build your UI using composable functions, the fundamental building blocks of Compose. This promotes modularity, reusability, and easier state management.
State Management with remember: Use remember to store and update UI state within composables. This ensures that your UI updates correctly when the state changes.
Lazy Compositions: Improve performance by using lazy to defer the composition of complex or expensive UI elements until they are actually needed.
2. Leverage Compose Modifiers
Visual Enhancements: Apply modifiers like padding, size, background, border, and clip to customize the appearance of your UI elements.
Layout Control: Use modifiers like width, height, fillMaxWidth, wrapContentSize, and aspectRatio to control the size and layout of your components.
Interaction Handling: Utilize modifiers like clickable, draggable, and pointerInput to handle user interactions with your UI.
3. Material Design 3 Support
Modern Look and Feel: Compose seamlessly integrates with Material Design 3, providing access to a rich set of pre-built components and styles.
Dynamic Theming: Easily adapt your UI to light and dark mode using Compose's built-in theming support.
Accessibility: Compose makes it easy to build accessible UIs that are usable by people with disabilities.
4. Advanced Techniques
Custom Layouts: Create custom layouts using Layout and SubcomposeLayout to achieve complex UI arrangements.
Animations and Transitions: Utilize Compose's animation system to create smooth and engaging user experiences.
Constraints: Define constraints on your UI elements using modifiers like constrainAs to control their size and position within the layout.
5. Best Practices
Keep Composable Functions Small and Focused: Break down complex UI into smaller, more manageable composable functions.
Use a Consistent Naming Convention: Choose clear and descriptive names for your composables and modifiers.
Write Tests: Write unit tests for your composable functions to ensure their correctness and maintainability
Clipping and Masking in Jetpack Compose
Discover how to use clipping and masking to shape your UI, control content visibility, and create unique and engaging user experiences
Clipping and masking are powerful techniques in Jetpack Compose that allow you to control the visible portions of your UI elements, creating visually interesting and unique effects.

Clipping
Clipping involves removing parts of a composable based on a defined shape. Only the content within the shape is displayed, while the rest is hidden
How to Clip in Compose:
-
Create a Shape: You can use predefined shapes like CircleShape, RoundedCornerShape, or create custom shapes using the Shape interface.
-
Apply the clip Modifier: Apply the clip modifier to the composable you want to clip. Pass the shape you created as an argument
@Preview @Composable fun CircularShape() {
Column { Text("Circular Shape", color = Color.Red, fontWeight = FontWeight.Bold) Image( painter = painterResource( R.drawable.dog ), contentDescription = "Custom shape", contentScale = ContentScale.Crop, modifier = Modifier .size(200.dp) .clip(CircleShape) ) } } |
Creating a Custom Shapes in compose
Oval Shape
@Preview @Composable fun SquashedOval() {
Column { Text("Circular Oval Shape", color = Color.Red, fontWeight = FontWeight.Bold) Image( painter = painterResource( R.drawable.dog ), contentDescription = "Custom shape", modifier = Modifier .size(100.dp) .clip(SquashedOvelShape()) )
} } |
Implementing Polygon Shapes in Jetpack Compose
@Preview @Composable fun CustomPolygonShape() {
//polygonShape.toPath().asComposePath() Column { Text("Custom Polygon Shape", color = Color.Red, fontWeight = FontWeight.Bold) Image( painter = painterResource( R.drawable.dog ), contentDescription = "Custom shape", contentScale = ContentScale.Crop, modifier = Modifier .size(200.dp) .clip(RoundedPolygonShape(getPolygon(0.4f)))
) Image( painter = painterResource( R.drawable.dog ), contentDescription = "Custom shape", contentScale = ContentScale.Crop, modifier = Modifier .size(200.dp) .clip(RoundedPolygonShape(getPolygon(1.4f)))
) } } |
We can indeed create various custom shapes for clipping in Compose. However, how would we approach a scenario where we need to display multiple user profile avatars overlapping each other (essentially stacking them)? Each avatar should be individually clipped into a circular shape

The Stacked Avatar Effect in Jetpack Compose
How can we do this?First create the avatar composable and clip the composable with a circle shape,Then using the drawWithContent modifier
we first call drawContent, which will draw the avatar itself then we draw a circle shape around the content
That will be used to clip the outline away from each avatar. We use a stroke style and draw the circle at the full size of the canvas with the color blue.
The next step is to stack the avatars on top of one another. We draw an avatar for each in our list of avatars with a particular stroke then we will set the offset of each avatar to increase the X offset as each item is iterated over.
Finally we achieved our requirement of a nice stack of avatars
@Preview @Composable private fun StackAcatars() { var size= Size(90.0f,90.0f) Box(modifier = Modifier.fillMaxWidth()) { var offset=0.dp for(k in 0..6) { Avatar(strokeWidth = 4.0f, modifier = Modifier.size(width = 120.dp,120.dp).offset(offset)) { Image(painter = painterResource(R.drawable.dog), contentScale = ContentScale.Crop, contentDescription = "") } offset+= 60.dp } } } @Composable fun Avatar( strokeWidth:Float, modifier:Modifier=Modifier, content:@Composable () -> Unit ) { Val stroke= remember (strokeWidth) { Stroke(width = strokeWidth) } Box(modifier= modifier .drawWithContent { drawContent() drawCircle( Color.Blue, size.minDimension / 2, size.center, style = stroke ) } .clip(CircleShape) ){ content() } } |
However, the black border is still present, we want the gradient background to be able to render between avatars by set the blend mode. The clear blend mode clears the pixels covered by the source in the destination
drawCircle( Color.Yellow, size.minDimension / 2, size.center, style = stroke, blendMode = BlendMode.Clear ) |
Masking
Masking is similar to clipping, but it allows for more control over the visibility of the content. You can use a mask to reveal or hide parts of a composable based on the opacity of the mask.
How to Mask in Compose:
-
Create a Mask: You can use a Path or a Bitmap as a mask.
-
Apply the mask Modifier: Apply the mask modifier to the composable you want to mask. Pass the mask you created as an argument
@Composable fun MaskedImage() { val maskPath = Path().apply { addRect(0f, 0f, 100f, 100f, Path.Direction.CW) addCircle(50f, 50f, 30f, Path.Direction.CW) // Create a circular hole in the mask } Image( painter = painterResource(id = R.drawable.your_image), contentDescription = null, modifier = Modifier .size(100.dp) .mask(maskPath) ) } |
Combine Clipping and Masking: You can combine clipping and masking to achieve more complex effects.
Custom Shapes: Create custom shapes using the Shape interface to achieve unique clipping or masking effects.
Animations: Animate clipping or masking to create dynamic and engaging UI elements
Article Contributed By :
|
|
|
|
970 Views |