Jetpack Compose Documentation
website·Indexed 32 days ago
https://jetpackcompose.cn/A comprehensive guide to Jetpack Compose, covering declarative UI development for Android. Includes tutorials on Composable functions, layout components like Row, Column, and Scaffold, animation APIs, and deep dives into internal principles such as the SlotTable, Snapshot system, and recomposition mechanics. Also features open-source project samples and implementation strategies for remote image loading using Picasso and Glide.
What's inside Jetpack Compose
- SubcomposeLayout allows the composition of child components to be deferred until the parent component's measurement phase. This provides stronger measurement customization capabilities, enabling a component to determine its own size based on the measurement information of other components. This can serve as an alternative to intrinsic measurements. Note that SubcomposeLayout has lower performance than the standard Layout component because it requires creating additional sub-compositions during the measurement phase; therefore, it should be used sparingly in performance-critical UI sections.
Overview of the Compose Composition to Rendering pipeline
The process of transforming Composable code into a rendered UI follows these steps:
- Compilation: The compiler inserts
startXXXGroupandendXXXGrouptemplates into the Composable source to enable tree traversal of the SlotTable. - Initial Composition:
startXXXGroupinserts Groups into the SlotTable, using keys to identify their positions. - Recomposition:
startXXXGrouptraverses and Diffs the SlotTable. Changes are recorded and lazily applied to both the SlotTable and theLayoutNodetree viaapplyChanges(). - Rendering: When a frame arrives,
LayoutNodeperforms measure, layout, and draw operations on the changed portions to refresh the UI.
- Compilation: The compiler inserts
Understand Jetpack Compose core concepts
Jetpack Compose is the modern toolkit for building native Android user interfaces. Unlike traditional imperative UI development, it uses a declarative design approach. Key benefits include simplified UI customization and real-time interactive previews, developed by the official Android team.Understand positional memoization in Jetpack Compose
Jetpack Compose uses positional memoization to persist state across recompositions. Unlike global memoization, positional memoization is tied to the Composable's location in the hierarchy. This allows values (such as those created viaremember) to remain consistent when a Composable is recomposed, enabling effective state management.@Composable fun App() { // Math.random() will return a new value on first composition, // but the same value during recompositions due to positional memoization. val x = remember { Math.random() } // ... }Reference for PointerInputChange properties and consumption APIs
ThePointerInputChangeclass provides detailed information about a pointer interaction and methods to manage its consumption state.class PointerInputChange( val id: PointerId, // Pointer ID val uptimeMillis: Long, // Timestamp val position: Offset, // Position relative to top-left of component val pressed: Boolean, // Whether the pointer is currently pressed val previousUptimeMillis: Long, // Previous timestamp val previousPosition: Offset, // Previous position val previousPressed: Boolean, // Previous pressed state val consumed: ConsumedData, // Consumption status val type: PointerType = PointerType.Touch // Pointer type (Touch, Mouse, Stylus, Eraser) )Understand Jetpack Compose Layout Principles
Compose uses a tree-based UI structure where each element is measured based on constraints (minimum and maximum width/height) provided by its parent. A critical performance rule in Compose is that single-pass measurement is mandatory: each child element can only be measured once. This prevents the exponential increase in measurement passes common in traditional View systems, ensuring high performance even with deep UI hierarchies.Arrange elements horizontally using the Row composable
TheRowcomposable is used to lay out its children in a horizontal sequence from left to right. It is often used in conjunction withColumnto build complex user interfaces. Key parameters includehorizontalArrangementfor controlling the horizontal distribution of children andverticalAlignmentfor controlling their vertical positioning.@Composable inline fun Row( modifier: Modifier? = Modifier, horizontalArrangement: Arrangement.Horizontal? = Arrangement.Start, verticalAlignment: Alignment.Vertical? = Alignment.Top, content: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? ): UnitUnderstand Intrinsic Measurement in Jetpack Compose
Intrinsic measurement allows a parent layout to pre-determine the width or height of its children before the formal measurement phase. This solves the problem where Compose prohibits multiple measurement passes for performance reasons, but a layout needs to know a child's size to calculate its own constraints (e.g., making a divider's height match the tallest sibling).Use the Surface component for Material Design containers
TheSurfacecomponent acts as a physical plane in Material Design. It is used to wrap other components to provide a consistent background, shape, border, and elevation. UsingSurfacehelps decouple visual styling (like shadows and rounded corners) from the internal layout logic, reducing the need for excessiveModifierchains on child components.Surface( shape = RoundedCornerShape(8.dp), elevation = 10.dp, modifier = Modifier .width(300.dp) .height(100.dp) ) { Row( modifier = Modifier.clickable { /* handle click */ } ) { Image( painter = painterResource(id = R.drawable.pic), contentDescription = "Description", modifier = Modifier.size(100.dp), contentScale = ContentScale.Crop ) Spacer(Modifier.padding(horizontal = 12.dp)) Column( modifier = Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center ) { Text( text = "Liratie", style = MaterialTheme.typography.h6 ) Spacer(Modifier.padding(vertical = 8.dp)) Text(text = "礼谙") } } }Display basic text in Jetpack Compose
TheTextcomposable is the fundamental component for displaying text in Compose. It can be used with hardcoded strings or by loading strings from Android resources usingstringResource.@Composable fun TextDemo() { // Basic usage Text("Hello World") // Loading from res/values/strings.xml Text(stringResource(id = R.string.content)) }Understand how MaterialTheme provides theme data
MaterialTheme works by usingCompositionLocalProviderto inject theme configurations (like colors, typography, and shapes) into the composable tree. A singleton objectMaterialThemeprovides a convenient way to access these values via properties that internally call.currenton the correspondingCompositionLocalinstances.object MaterialTheme { val colors: Colors @Composable @ReadOnlyComposable get() = LocalColors.current val typography: Typography @Composable @ReadOnlyComposable get() = LocalTypography.current val shapes: Shapes @Composable @ReadOnlyComposable get() = LocalShapes.current } // The underlying CompositionLocal internal val LocalColors = staticCompositionLocalOf { lightColors() }Understand the Jetpack Compose Modifier interface structure
The
Modifieris an interface used to decorate UI components. Its final effect depends on the order of calls because Compose executes modifiers sequentially according to the constructed chain.There are three primary implementations of the
Modifierinterface:- Companion Object
Modifier: The entry point used when callingModifier.xxx(). It acts as the root of the chain. Modifier.Element: The actual functional modifiers (e.g.,SizeModifiercreated byModifier.size()). Most specific modifiers implement this sub-interface or its descendants (likeLayoutModifierorDrawModifier).CombinedModifier: An internal data structure used to link multiple modifiers together into a chain.
- Companion Object