Master Jetpack Compose: A Beginner’s Guide to Modern Android UI Development
This article introduces Jetpack Compose, Google’s modern declarative UI toolkit for Android, explaining its origins, core concepts of declarative UI, basic usage, essential components like Text, Button, Image, layout containers, modifiers, state management, and provides practical code examples to help developers build efficient, modern Android interfaces.
Compose Overview
Jetpack Composewas announced at Google I/O 2019 and reached its stable 1.0.0 release in July 2021. It enables Android UI development with significantly less Kotlin code and a more intuitive API.
Why Compose Was Introduced
Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.
Traditional XML‑based UI becomes cumbersome as screens grow more complex, requiring manual synchronization of view states. Compose solves this by using immutable, declarative UI components annotated with @Composable. When state changes, the composable function re‑executes, automatically updating the UI.
What Declarative UI Means
In imperative UI (e.g., XML + findViewById), developers manually locate views and invoke methods to change their properties. Declarative UI describes the desired UI state; the framework handles transitions.
// Imperative example
var tv: TextView = findViewById(R.id.tv)
tv.setColor(red) // Declarative example
Text("hello ${name}", modifier = Modifier.background(color = Color.Blue))Basic Usage
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyApplicationTheme {
Greeting("Android")
}
}@Composable : Only functions annotated with this can call other composable functions.
@Preview : Shows a preview in Android Studio without running the app.
setContent : Replaces the traditional setContentView by providing a composable lambda.
Core Components
Text
The Text composable is analogous to TextView. Key properties include: text: String – the displayed text. modifier: Modifier – layout and styling. color: Color – text color (e.g., Color.Blue or Color(0xFF000000)). fontSize: TextUnit – size such as 20.sp.
fontFamily, fontWeight, lineHeight, letterSpacing, textDecoration, maxLines, fontStyle, textAlign, onTextLayout, overflow– additional styling options.
Text(
text = "Hello BillionBottle",
modifier = Modifier.padding(5.dp),
color = Color.Blue,
textAlign = TextAlign.Start,
textDecoration = TextDecoration.LineThrough,
fontStyle = FontStyle.Italic,
maxLines = 1
)Button
Buttons handle click events and expose several customizable properties:
onClick: () -> Unit modifier: Modifier enabled: Boolean shape: Shape border: BorderStroke? elevation: ButtonElevation? contentPadding: PaddingValues colors: ButtonColors content: @Composable () -> Unit Button(
onClick = {},
modifier = Modifier.padding(12.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Green,
contentColor = Color.Blue
),
elevation = ButtonDefaults.elevation(
defaultElevation = 12.dp,
pressedElevation = 12.dp
),
border = BorderStroke(width = 1.dp, color = Color.Blue)
) {
Text(text = "BillionBottle")
}Image
The Image composable replaces ImageView. Important properties: bitmap: ImageBitmap – directly provide a bitmap. contentDescription: String? – accessibility description.
modifier: Modifier alignment: Alignment contentScale: ContentScale alpha: Float colorFilter: ColorFilter Image(
painter = painterResource(R.drawable.xxx),
contentDescription = ""
)Surface
Surfaceprovides a background container for custom components.
modifier: Modifier shape: Shape(default RectangleShape) color: Color – background color. contentColor: Color – default text color inside the surface.
border: Border? elevation: Dp content: @Composable () -> Unit Surface(modifier = Modifier.padding(4.dp), color = Color.Gray) {
Column {
Text(modifier = Modifier.align(Alignment.CenterHorizontally), text = "custom")
Image(
painter = ColorPainter(color = Color.Green),
contentDescription = "image color"
)
}
}Canvas
Canvasallows custom drawing within a defined area. Size is set via Modifier.size or Modifier.fillMaxSize. Drawing commands such as drawLine, drawCircle, drawArc, etc., are available through DrawScope.
Canvas(modifier = Modifier.fillMaxSize()) {
val canvasWidth = size.width
val canvasHeight = size.height
// Draw a blue line from top‑right to bottom‑left
drawLine(
start = Offset(x = canvasWidth, y = 0f),
end = Offset(x = 0f, y = canvasHeight),
color = Color.Blue
)
// Draw a green circle at (200,1200) with radius 120
drawCircle(color = Color.Green, center = Offset(200f, 1200f), radius = 120f)
}Layout Containers
Column
Arranges children vertically, similar to LinearLayout with verticalArrangement and horizontalAlignment controls.
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {
val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
Layout(content = { ColumnScopeInstance.content() }, measurePolicy = measurePolicy, modifier = modifier)
}Common verticalArrangement values: Arrangement.Bottom, Arrangement.Center, Arrangement.SpaceBetween, Arrangement.SpaceEvenly, Arrangement.SpaceAround.
Common horizontalAlignment values: Alignment.Start, Alignment.End, Alignment.CenterHorizontally.
@Composable
fun columnColumn() {
Column(
modifier = Modifier.height(100.dp).padding(5.dp),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.End
) {
Text("安卓")
Text("BillionBottle")
}
}Row
Arranges children horizontally, mirroring LinearLayout with horizontalArrangement and verticalAlignment.
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) {
val measurePolicy = rowMeasurePolicy(horizontalArrangement, verticalAlignment)
Layout(content = { RowScopeInstance.content() }, measurePolicy = measurePolicy, modifier = modifier)
} @Composable
fun rowShow() {
Row(
modifier = Modifier.width(200.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start
) {
Text("安卓")
Text("BillionBottle")
}
}Box
Stacks children on top of each other, similar to FrameLayout. The contentAlignment parameter controls alignment of children.
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {
val measurePolicy = rememberBoxMeasurePolicy(contentAlignment, propagateMinConstraints)
Layout(content = { BoxScopeInstance.content() }, measurePolicy = measurePolicy, modifier = modifier)
} @Composable
fun boxLayout() {
Box(
contentAlignment = Alignment.BottomCenter,
modifier = Modifier.width(100.dp).height(50.dp).padding(bottom = 10.dp)
) {
Text("BillionBottle", modifier = Modifier.background(Color.Yellow))
Text("安卓", modifier = Modifier.background(Color.Gray))
}
}Modifiers
Modifiers extend a composable’s behavior (size, background, click handling, etc.) via a chainable Modifier object. Common modifiers include background, height, size, clickable, and many others.
Column(
modifier = Modifier
.width(100.dp)
.height(100.dp)
) {
Text("BillionBottle")
Icon(
Icons.Filled.Favorite,
contentDescription = "Favorite",
modifier = Modifier
.background(Color.Green)
.size(ButtonDefaults.IconSize)
.padding(2.dp)
)
}Changing the order of .size and .padding can noticeably affect the final layout.
State Management
Compose’s UI reacts to changes in observable state objects such as MutableState<T>. Create mutable state with mutableStateOf and remember it across recompositions using remember or rememberSaveable (which survives configuration changes).
interface MutableState<T> : State<T> {
override var value: T
}
val state = remember { mutableStateOf("") }
var value by remember { mutableStateOf("") }
val (value, setValue) = remember { mutableStateOf("") }Example using OutlinedTextField to edit a string and display it above the field:
@Composable
fun Greeting(name: String) {
var info by remember { mutableStateOf(Info("")) }
MyApplicationTheme {
Surface(color = MaterialTheme.colors.background) {
Column(modifier = Modifier.padding(16.dp)) {
if (info.content.isNotEmpty()) {
Text(text = info.content)
}
OutlinedTextField(
value = info.content,
onValueChange = { info = Info(it) },
label = { Text("title") }
)
}
}
}
}When the composable is destroyed due to configuration changes (e.g., rotation), remember loses its data. Use rememberSaveable with a StateSaver (e.g., parcelable, mapSaver, listSaver) to persist state.
@Parcelize
data class Info(val content: String) : Parcelable
var value by rememberSaveable { mutableStateOf(Info("")) }Conclusion
This article provided a concise introduction to Jetpack Compose’s fundamental concepts, core UI components, layout containers, modifiers, and state handling. For deeper exploration, refer to the official documentation as the library continues to evolve with new features.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
BaiPing Technology
Official account of the BaiPing app technology team. Dedicated to enhancing human productivity through technology. | DRINK FOR FUN!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
