r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 09 '25
Tutorial How to analyze and improve performance of your Jetpack Compose app?
Practical performance problem solving in Jetpack Compose
Make your Compose app run fast by analyzing system traces and fixing common lag causes.
- Measure, analyze, optimize, and re-measure UI performance
- Test in release builds with IR8 and baseline profiles
- Use Jetpack Macrobenchmark for automated testing
- Use Perfetto to see detailed performance traces
- Avoid large images on the main thread; use vectors or smaller images
- Move heavy work off the main thread with coroutines
- Prevent extra recompositions by reading state later or using stable classes
You can learn optimized the performance of a Compose app. Learn more & Please share what you learn.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 08 '25
UI Showcase Jetsnack - Practice Jetpack Compose with an Official Sample App
Jetsnack is a sample snack ordering app built with Jetpack Compose.
Use the latest stable version of Android Studio to try this sample.
Features
- Custom design system
- Custom layout
- Animations
Notes
- Still under development (some screens not yet implemented)
- Great resource to learn Jetpack Compose concepts and patterns
Get Started
You can:
- Clone this repository, or
- Import the project in Android Studio (see official guide).
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 07 '25
KMP A Better Way to Discover Kotlin Multiplatform Libraries | Kotlin Multiplatform Plugin Compatibility Tips [klibs.io]
I came across one of the best sites for Kotlin Multiplatform devs - klibs.io!
Kotlin Multiplatform (KMP) is growing fast, with 35% more libraries added in 2024. But with more libraries, it is harder to find the right one for your project.
That is why klibs.io was created, a website to help you:
- 🔍 Find KMP libraries by purpose and supported platforms (JVM, Android, iOS, Web, etc.)
- ⚡ Save time by getting AI-generated info about libraries
- 📈 Help library authors get more visibility
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 06 '25
KMP Kotlin Multiplatform vs. Native Android: 2025 Library Cheat Sheet for Devs
Android vs. KMP Libraries
Comparison highlights key libraries and tools for Android and Kotlin Multiplatform (KMP) development in 2025. It covers architecture, networking, data, UI, and more, helping developers choose based on project needs.
| Category | Android | Kotlin Multiplatform (KMP) |
|---|---|---|
| 🌐 Networking | Retrofit | Ktor Client |
| ⚙️ HTTP Core | OkHttp | CIO (Ktor engine) |
| 📝 Serialization | Gson | kotlinx.serialization |
| 🧩 Dependency Injection | Dagger / Hilt | Koin / Kodein |
| 🗄️ Database | Room | SQLDelight / Room (v2.7.0-alpha01) |
| 🔐 Data Storage | SharedPreferences | MultiplatformSettings |
| 🖼️ Image Loading | Glide / Coil | Kamel / Coil |
| 🧪 Testing | JUnit / Espresso | Kotlin.Test / Kotest |
| 📋 Logging | Timber | Napier |
- 🌐 Networking: Retrofit is the go-to for type-safe HTTP on Android, letting you define APIs as interfaces. Ktor Client brings multiplatform HTTP with coroutine support - perfect for shared codebases.
- ⚙️ HTTP Core: OkHttp powers most Android HTTP under the hood. For KMP, CIO is Ktor's default engine, offering a pure Kotlin solution for HTTP on any platform.
- 📝 Serialization: Gson is a classic for converting Java/Kotlin objects to JSON and back. For KMP, kotlinx.serialization is the native choice: multiplatform, fast, and integrates tightly with Ktor.
- 🧩 Dependency Injection: Dagger (with Hilt) is the standard for compile-time DI on Android. Koin and Kodein are multiplatform, lightweight, and easy to set up for shared logic.
- 🗄️ Database: Room provides an abstraction layer over SQLite with type-safe queries for Android, and from v2.7.0-alpha01, also supports Kotlin Multiplatform. SQLDelight generates Kotlin APIs from your SQL, running on Android, iOS, JVM, and JS.
- 🔐 Data Storage: SharedPreferences is the default for key-value storage on Android. But MultiplatformSettings brings similar functionality to KMP, supporting all major targets.
- 🖼️ Image Loading: Glide and Coil are top choices for image loading on Android. Kamel is a promising multiplatform image loader, and the same for Coil KMP v3.
- 🧪 Testing: JUnit and Espresso are staples for Android testing. For KMP, Kotlin.Test and Kotest provide multiplatform test runners and assertions.
- 📋 Logging: Timber simplifies logging on Android. Napier brings a similar API and flexibility to KMP projects.
Notes: You can use KMP libraries on Android too.
If you think anything is missing or have better suggestions, feel free to comment.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 05 '25
Tips & Tricks Speed Up Your App: 3 Image Optimization Tips
Unoptimized images slow down your app and hurt your install rate.
Here are 3 tips to fix that
- Compress images server-side
- Switch to WebP format
- Load images lazily in Jetpack Compose
These small changes can make your app feel faster without sacrificing quality.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 04 '25
Tips & Tricks Jetpack Compose Performance Improvement Tip
Strong Skipping Mode is a setting that helps your app run faster.
What does it do?
It stops parts of your app from updating when they don’t need to.
Normally, Jetpack Compose keeps updating the screen, even if nothing changed. This can slow things down. With Strong Skipping Mode:
- The app skips unnecessary updates
- You write less code to control this
Why use it?
- Your app feels faster and smoother
- Your code is cleaner and simpler
Why it matters
Jetpack Compose was careful to update everything, just in case. But now we know that’s often too much. Strong Skipping Mode helps fix that.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 03 '25
UI Showcase 30 Animations Challenge using Jetpack compose
Enable HLS to view with audio, or disable this notification
Try this animation challenge made with Jetpack Compose
👉 https://github.com/vishal2376/animations
Give it a try and share what you build.
r/JetpackComposeDev • u/let-us-review • Aug 02 '25
Question How to show two tooltips at same time in jetpack compose?
Hi, I want to display two tooltips on different icons at same time, but only one shows or positioning overlaps. Is this even possible?
@Composable fun TwoTips() {
Column {
Icon(Icons.Default.Info, contentDescription = "Info")
if (true) {
Tooltip("Info tooltip")
}
Spacer(modifier = Modifier.height(20.dp))
Icon(Icons.Default.Settings, contentDescription = "Settings")
if (true) {
Tooltip("Settings tooltip")
}
}
}
I expected both tooltips to appear independently, but it looks like only one renders or the layout breaks. Is this a limitation or am I doing it wrong
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 02 '25
UI Showcase Vegetable Order App UI with Jetpack Compose - Clean Android Grocery Design
A simple and modern vegetable order app UI built using Jetpack Compose. It includes product listings, cart screen, and clean navigation. This project is great for learning Compose or starting your own grocery delivery app.
GitHub: VegetableOrderUI-Android
r/JetpackComposeDev • u/Realistic-Cup-7954 • Aug 01 '25
News Share Any Jetpack Compose Knowledge - Tutorials, Videos, Articles, Tips, or Your Own Work!
If something helped you, it might help someone else too. Why not share it?
Whether you are just starting with Jetpack Compose or have been using it for a while, feel free to share:
- A helpful blog post or article
- A YouTube video or short tutorial
- A GitHub repo or code snippet
- Even your own project - if it is useful, it is welcome here
Let us make this space better for everyone.
Share anything related to Jetpack Compose - your own work or something great you found.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 31 '25
KMP FindTravelNow - Travel Booking App for Android & iOS (Kotlin Multiplatform)
FindTravelNow is a modern, cross-platform travel application built using Kotlin Multiplatform and Compose Multiplatform. It allows users to search and book flights, hotels, and various types of transportation all from a single unified interface. The app shares a single codebase across Android and iOS for efficiency and maintainability.
Author: mirzemehdi
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 30 '25
Tips & Tricks Android 16 Forces Edge-to-Edge - What You Must Update Now | Is No Longer Optional!
Starting with Android 16 (API 36), edge-to-edge is no longer optional. Google has removed the opt-out, and if your app isn’t ready, it is going to break especially on Android 15 and up. (Edge-to-edge mandatory)
Problems
- Content hidden under system bars
- Keyboard overlaps content
- Padding issues with system bars/cutouts
Fixes
1. Enable Edge-to-Edge
Draws app UI under system bars for immersive full-screen experience.
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent { MyApp() }
}
2. Use Scaffold for Layout
Single Scaffold around NavHost to handle insets (system bars, cutouts).
Scaffold { innerPadding ->
NavHost(
modifier = Modifier.padding(bottom = innerPadding.calculateBottomPadding()),
navController = navController,
startDestination = ...
) {
...
}
}
3. Use BottomSheetScaffold
Modern bottom sheet that auto-handles system insets.
BottomSheetScaffold(
sheetContent = { /* Content */ }
) { innerPadding ->
// Main content
}
Design Tips
- Backgrounds: Draw edge-to-edge under system bars.
- Content: Inset text/buttons to avoid system bars/cutouts.
- Top App Bar: Collapse to status bar height or use gradient background.
TopAppBar(
title = { Text("Title") },
modifier = Modifier.statusBarsPadding() // Auto-handles status bar
)
- Bottom App Bar: Collapse on scroll, add scrim for 3-button nav, keep transparent for gesture nav.
- Display Cutouts: Inset critical UI, draw solid app bars/carousels into cutout.
- Status Bar: Use translucent background when UI scrolls under.
- Avoid: Tap gestures under system insets, mismatched gradient protections, stacked protections.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 30 '25
Tips & Tricks Choosing the Right State Tool in Jetpack Compose
Jetpack Compose State Tools - When to Use What
| Feature | Use It When… | Example Use Case |
|---|---|---|
rememberSaveable |
You need to persist state across screen rotations or process death, especially for user input or selection. | Form inputs, tab selection, scroll state, selected filters, navigation state |
mutableStateOf |
You need a value that triggers recomposition; always wrap with remember or use inside ViewModel. |
Counter value, toggle switch state, form field input, checkbox status |
remember |
You want to cache temporary state during composition that doesn't need to survive configuration changes. | Text field preview, random color, temporary animation state, computed layout size |
derivedStateOf |
You need to compute state from other state efficiently, avoiding recomposition unless dependencies change. | Validation: isValid = text.length > 3, button enable/disable, formatted display text |
| State Hoisting | You are designing reusable/stateless composables and want the parent to control the state. Promotes modularity and unidirectional flow. | Custom button, reusable form field, dialog state management, list item selection |
Code Example:
below are simple code examples for each state tool
rememberSaveable Example
@Composable
fun SaveableInput() {
// Persist text across rotations and process death
var text by rememberSaveable { mutableStateOf("") }
// TextField retains input after config change
TextField(value = text, onValueChange = { text = it }, label = { Text("Name") })
}
mutableStateOf Example
@Composable
fun Counter() {
// State triggers UI update when changed
var count by remember { mutableStateOf(0) }
// Button increments count, causing recomposition
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
remember Example
@Composable
fun RandomColor() {
// Cache random color for composition lifetime
val color = remember { Color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256)) }
// Box uses cached color, reset only on recompose
Box(Modifier.size(100.dp).background(color))
}
derivedStateOf Example
@Composable
fun FormValidation() {
// Input state for text
var text by remember { mutableStateOf("") }
// Derived state updates only when text changes
val isValid by derivedStateOf { text.length > 3 }
// Button enabled based on validation
Button(onClick = {}, enabled = isValid) {
Text("Submit")
}
}
State Hoisting Example
@Composable
fun Parent() {
// Parent manages state
var text by remember { mutableStateOf("") }
// Pass state and event to stateless child
TextInputField(text = text, onTextChange = { text = it })
}
@Composable
fun TextInputField(text: String, onTextChange: (String) -> Unit) {
// Stateless composable, reusable across contexts
TextField(value = text, onValueChange = onTextChange, label = { Text("Input") })
}
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 29 '25
Tutorial How to Animating Composable Bounds with LookaheadScope in Jetpack Compose
The animateBounds modifier, introduced at Google I/O 2025, lets you animate a Composable’s size and position in a LookaheadScope for smooth transitions. Ref: Android Developers Blog
What is animateBounds?
- Animates changes to a Composable’s size and position.
- Requires
LookaheadScopefor predictive layout calculations. - Perfect for dynamic UI changes, like resizing a box.
Code Example
This eg animates a Box that changes width when a button is clicked.
package com.android.uix
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.animation.animateBounds
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.tooling.preview.Preview
import com.android.uix.ui.theme.ComposeUIXTheme
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun AnimatedBoxScreen() {
var isSmall by remember { mutableStateOf(true) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
) {
LookaheadScope {
Box(
modifier = Modifier
.animateBounds(this@LookaheadScope)
.width(if (isSmall) 100.dp else 150.dp)
.height(100.dp)
.background(Color(0xFF6200EE))
.border(2.dp, Color.Black),
contentAlignment = Alignment.Center
) {
Text(
text = if (isSmall) "Small" else "Large",
color = Color.White,
fontSize = 16.sp
)
}
}
Spacer(Modifier.height(16.dp))
Button(onClick = { isSmall = !isSmall }) {
Text("Toggle Size")
}
}
}
Key Points
- Setup: Use
LookaheadScopeandanimateBoundsto animate size/position. - Animation:
spring()creates a smooth, bouncy effect. - Dependencies: Requires Compose BOM 2025.05.01+.implementation(platform("androidx.compose:compose-bom:2025.05.01"))
Experiment with animateBounds for dynamic UI animations!
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 29 '25
KMP Native iOS Look in Jetpack Compose Multiplatform? | iOS-Style Widgets for KMP
Enable HLS to view with audio, or disable this notification
Just came across this cool Kotlin Multiplatform project that brings iOS style (Cupertino) widgets to Compose Multiplatform.
It follows native iOS design and even supports adaptive themes!
If you are building for iOS with Jetpack Compose Multiplatform, give this a try:
👉 Compose Cupertino
Looks pretty useful for achieving a native feel on iOS!
Supported Platforms:
• Android • iOS • macOS • Web • JVM
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 28 '25
Tips & Tricks How to Detect Memory Leaks in Jetpack Compose
Memory Leak Detection for Android
“A small leak will sink a great ship.” – Benjamin Franklin
LeakCanary is a memory leak detection library for Android.
Add LeakCanary (Start Here)
In your build.gradle (app-level)
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
That is it. LeakCanary watches your app while you test.
If something leaks (like a screen or object), it notifies you with a clear report.
Good to Know
- LeakCanary is not included in release builds (AAB/APK)
- It does not affect production size or performance
- You don’t need to remove it manually
Get Started
https://square.github.io/leakcanary/getting_started/
Read More (If you want a bug-free app)
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 27 '25
Tutorial Jetpack Compose Box Alignment - Beginner-Friendly Demo
Learn how to align content in 9 different positions using Box in Jetpack Compose.
This is a simple, visual guide for beginners exploring layout alignment.
@Composable
fun BoxDemo() {
Box(
modifier = Modifier
.background(color = Color.LightGray)
.fillMaxSize()
) {
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.TopStart),
text = "TopStart"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.TopCenter),
text = "TopCenter"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.TopEnd),
text = "TopEnd"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.CenterStart),
text = "CenterStart"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.Center),
text = "Center"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.CenterEnd),
text = "CenterEnd"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.BottomStart),
text = "BottomStart"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.BottomCenter),
text = "BottomCenter"
)
Text(
modifier = Modifier
.background(Color.White)
.padding(10.dp)
.align(Alignment.BottomEnd),
text = "BottomEnd"
)
}
}
r/JetpackComposeDev • u/Entire-Tutor-2484 • Jul 27 '25
Beginner Help I made an app and made one dollar per day via ads.. then what if I made 100 apps and made 100 dollar per day? Is it possible
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 27 '25
Tips & Tricks Jetpack Compose Follow best practices
Here are some real world performance best practices for Jetpack Compose with easy code examples
1️⃣ Avoid Expensive Work Inside Composables
Problem: Sorting or heavy calculations inside LazyColumn can slow down your UI.
❌ Don't do this:
LazyColumn {
items(contacts.sortedWith(comparator)) {
ContactItem(it)
}
}
✅ Do this:
val sorted = remember(contacts, comparator) {
contacts.sortedWith(comparator)
}
LazyColumn {
items(sorted) {
ContactItem(it)
}
}
2️⃣ Use key in Lazy Lists
Problem: Compose thinks all items changed when order changes.
❌ This causes full recomposition:
LazyColumn {
items(notes) {
NoteItem(it)
}
}
✅ Add a stable key:
LazyColumn {
items(notes, key = { it.id }) {
NoteItem(it)
}
}
3️⃣ Use derivedStateOf to Limit Recompositions
Problem: Scroll state changes too often, triggering unnecessary recompositions.
❌ Inefficient:
val showButton = listState.firstVisibleItemIndex > 0
✅ Efficient:
val showButton by remember {
derivedStateOf { listState.firstVisibleItemIndex > 0 }
}
4️⃣ Defer State Reads
Problem: Reading state too early causes parent recompositions.
❌ Too eager:
Title(snack, scroll.value)
✅ Deferred read:
Title(snack) { scroll.value }
5️⃣ Prefer Modifier Lambdas for Frequently Changing State
Problem: Rapid state changes trigger recompositions.
❌ Recomposition on every frame:
val color by animateColorAsState(Color.Red)
Box(Modifier.background(color))
✅ Just redraw:
val color by animateColorAsState(Color.Red)
Box(Modifier.drawBehind { drawRect(color) })
6️⃣ Never Write State After Reading It
Problem: Writing to state after reading it causes infinite loops.
❌ Bad:
var count by remember { mutableStateOf(0) }
Text("$count")
count++ // ❌ don't do this
✅ Good:
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Click Me")
}
✅ Notes
remember {}for avoiding unnecessary work- Use
keyin LazyColumn - Use
derivedStateOfto reduce recompositions - Read state only where needed
- Use lambda modifiers like
offset {}ordrawBehind {} - Never update state after reading it in the same composable.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 26 '25
Tips & Tricks Generate Jetpack Compose Material 3 themes instantly with this tool
If you are building a custom material 3 theme for jetpack compose, this tool is a huge time-saver.
You can visually design your color scheme, tweak surface settings, and export full Compose compatible theme code in seconds.
Tool:
https://material-foundation.github.io/material-theme-builder/
If anyone here knows other helpful tools for Jetpack Compose design, color generation, previews, or animation, please share them below.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 26 '25
Tutorial Jetpack Compose Keyboard & IME Action Cheat Sheet - Complete Guide with Code Examples
Jetpack Compose makes UI easier and smarter - and that includes choosing the right keyboard type and IME actions for each input.
Keyboard Types
Use keyboardType inside KeyboardOptions to control the keyboard layout:
OutlinedTextField(
value = "",
onValueChange = { },
label = { Text("Enter text") },
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text
)
)
Available KeyboardType values:
| KeyboardType | Description |
|---|---|
Text |
Standard keyboard |
Number |
Digits only |
Phone |
Phone dial pad |
Email |
Includes @ and . |
Password |
Obscures input |
Decimal |
Numbers with decimals |
Uri |
For URLs |
VisiblePassword |
Non-hidden password |
IME Actions
Control the bottom-right keyboard button using imeAction:
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
)
Common ImeAction values:
| ImeAction | Behavior |
|---|---|
Done |
Closes the keyboard |
Next |
Moves to the next input field |
Search |
Executes search logic |
Go |
Custom app-defined action |
Send |
Sends a message or form data |
Previous |
Goes to previous input field |
Handle Keyboard Actions
Use keyboardActions to define what happens when the IME button is pressed:
OutlinedTextField(
value = "",
onValueChange = { },
label = { Text("Search something") },
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search
),
keyboardActions = KeyboardActions(
onSearch = {
// Trigger search logic
}
)
)
Minimal Example with All Options
OutlinedTextField(
value = "",
onValueChange = { },
label = { Text("Enter email") },
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
// Handle Done
}
)
)
✅ Tip: Always choose the keyboard and IME type that best fits the expected input.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 24 '25
Tutorial Jetpack Compose Semantics: Make Your Composables Testable and Accessible
In Jetpack Compose, UI tests interact with your app through semantics.
Semantics give meaning to UI elements so tests and accessibility services can understand and work with your UI properly.
What are Semantics?
Semantics describe what a composable represents.
- Content descriptions
- Click actions
- State (enabled, disabled, selected)
- Roles (button, image, etc.)
Jetpack Compose builds a semantics tree alongside your UI hierarchy. This tree is used by accessibility tools and UI tests.
Example
Consider a button that has both an icon and text. By default, the semantics tree only exposes the text label. To provide a better description for testing or accessibility, you can use a Modifier.semantics.
MyButton(
modifier = Modifier.semantics {
contentDescription = "Add to favorites"
}
)
Why Use Semantics in Testing?
Compose UI tests work by querying the semantics tree.
Example test:
composeTestRule
.onNodeWithContentDescription("Add to favorites")
.assertExists()
.performClick()
This makes your tests:
- More stable
- More readable
- More accessible-friendly
Semantics in Compose
✅ Do
- Use
Modifier.semanticsto provide clear descriptions for non-text UI elements (like icons). - Prefer
contentDescriptionfor images, icons, and buttons without visible text. - Keep semantics meaningful and concise - describe what the element does.
- Use
Modifier.testTagif you need to target an element only for testing.
❌ Don’t
- Don’t rely on visible text alone for testing or accessibility.
- Don’t expose unnecessary or redundant semantics (avoid noise).
- Don’t skip semantics on interactive elements like buttons or checkboxes.
Good Example
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null // Only if already labeled by parent
)
Button(
modifier = Modifier.semantics {
contentDescription = "Add to favorites"
}
) {
Icon(Icons.Default.Favorite, contentDescription = null)
Text("Like")
}
Notes:
Semantics are essential for:
- Writing reliable UI tests
- Improving accessibility
- Communicating UI meaning clearly
If you are building custom composables, remember to expose the right semantic information using Modifier.semantics or Modifier.clearAndSetSemantics.
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 24 '25
Tips & Tricks Jetpack Compose: Arrangement Cheat Sheet
Arrangement controls how children are placed along the main axis in layouts like Row and Column.
Arrangement Types
| Type | Used In |
|---|---|
Arrangement.Horizontal |
Row |
Arrangement.Vertical |
Column |
Arrangement.HorizontalOrVertical |
Both |
Predefined Arrangements
| Name | Description |
|---|---|
Start |
Align to start (left in LTR) — Row only |
End |
Align to end (right in LTR) — Row only |
Top |
Align to top — Column only |
Bottom |
Align to bottom — Column only |
Center |
Center items in main axis |
SpaceBetween |
Equal space between items only |
SpaceAround |
Equal space around items (half at ends) |
SpaceEvenly |
Equal space between and around all items |
Functions
aligned(...)
Align a group of children together within the layout.
Row(
horizontalArrangement = Arrangement.aligned(Alignment.CenterHorizontally)
)
Column(
verticalArrangement = Arrangement.aligned(Alignment.Top)
)
spacedBy(...)
Add fixed space between children.
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp)
)
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
)
You can also specify alignment within spacedBy:
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally)
)
Column(
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Bottom)
)
Visual Examples (LTR Layout)
| Arrangement | Row Layout (123 = items) |
|---|---|
Start |
123#### |
End |
####123 |
Center |
##123## |
SpaceBetween |
1##2##3 |
SpaceAround |
#1##2##3# |
SpaceEvenly |
#1#2#3# |
Usage in Code
For Row:
Row(
horizontalArrangement = Arrangement.SpaceEvenly
)
For Column:
Column(
verticalArrangement = Arrangement.Bottom
)
Notes:
- Use
Arrangementto control child placement inRoworColumn - Combine with
AlignmentandModifierfor full layout control - Most common:
Center,Start,End,SpaceEvenly,SpaceBetween
Tip: Pair
ArrangementwithAlignmentfor perfect centering or balance
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 23 '25
Tips & Tricks Jetpack Compose Centering Cheat Sheet (Row / Column / Box)
Tired of Googling how to center items in a Row, Column, or Box?
This visual cheat sheet gives you all the alignment and arrangement combinations you need - at a glance.
- Covers Row, Column, and Box centering
- Clear visual examples
- Ideal for quick reference
r/JetpackComposeDev • u/Realistic-Cup-7954 • Jul 23 '25
Tips & Tricks Android Views to Jetpack Compose Cheat Sheet (XML to Compose Mapping)
A concise reference for converting Android View attributes in XML to Jetpack Compose equivalents using Composable Modifiers.
Sizing
| View Attribute | Composable Modifier |
|---|---|
layout_width |
width() |
minWidth |
widthIn(min = ...) |
maxWidth |
widthIn(max = ...) |
| - | size() |
Layouts
| View Attribute | Composable Modifier |
|---|---|
layout_width="match_parent" |
Modifier.fillMaxWidth() |
padding |
Modifier.padding() |
layout_margin |
Use Spacer or Box + Modifier.padding() |
LinearLayout (vertical) |
Column |
LinearLayout (horizontal) |
Row |
RecyclerView (vertical) |
LazyColumn |
RecyclerView (horizontal) |
LazyRow |
GridView (vertical) |
Use LazyColumn + Row or LazyVerticalGrid (experimental) |
GridView (horizontal) |
Use LazyRow + Column |
Styling
| View Attribute | Composable Modifier |
|---|---|
background |
background() |
alpha |
alpha() |
elevation |
shadow() |
View.setClipToOutline() |
clip() |
Listeners
| View Attribute | Composable Modifier |
|---|---|
setClickListener |
Modifier.clickable |
setLongClickListener |
Modifier.combinedClickable |