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.

Tokens
69.4K
Snippets
275
Records
315
Agent score
55%

What's inside Jetpack Compose

  1. Overview of SubcomposeLayout

    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.
  2. Overview of the Compose Composition to Rendering pipeline

    The process of transforming Composable code into a rendered UI follows these steps:

    1. Compilation: The compiler inserts startXXXGroup and endXXXGroup templates into the Composable source to enable tree traversal of the SlotTable.
    2. Initial Composition: startXXXGroup inserts Groups into the SlotTable, using keys to identify their positions.
    3. Recomposition: startXXXGroup traverses and Diffs the SlotTable. Changes are recorded and lazily applied to both the SlotTable and the LayoutNode tree via applyChanges().
    4. Rendering: When a frame arrives, LayoutNode performs measure, layout, and draw operations on the changed portions to refresh the UI.
  3. 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.
  4. 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 via remember) 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() }
      // ...
    }
  5. Reference for PointerInputChange properties and consumption APIs

    The PointerInputChange class 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)
    )
  6. 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.
  7. Arrange elements horizontally using the Row composable

    The Row composable is used to lay out its children in a horizontal sequence from left to right. It is often used in conjunction with Column to build complex user interfaces. Key parameters include horizontalArrangement for controlling the horizontal distribution of children and verticalAlignment for 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)?
    ): Unit
  8. Understand 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).
  9. Use the Surface component for Material Design containers

    The Surface component acts as a physical plane in Material Design. It is used to wrap other components to provide a consistent background, shape, border, and elevation. Using Surface helps decouple visual styling (like shadows and rounded corners) from the internal layout logic, reducing the need for excessive Modifier chains 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 = "礼谙")
        }
      }
    }
  10. Display basic text in Jetpack Compose

    The Text composable is the fundamental component for displaying text in Compose. It can be used with hardcoded strings or by loading strings from Android resources using stringResource.
    @Composable
    fun TextDemo() {
        // Basic usage
        Text("Hello World")
    
        // Loading from res/values/strings.xml
        Text(stringResource(id = R.string.content))
    }
  11. Understand how MaterialTheme provides theme data

    MaterialTheme works by using CompositionLocalProvider to inject theme configurations (like colors, typography, and shapes) into the composable tree. A singleton object MaterialTheme provides a convenient way to access these values via properties that internally call .current on the corresponding CompositionLocal instances.
    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() }
  12. Understand the Jetpack Compose Modifier interface structure

    The Modifier is 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 Modifier interface:

    1. Companion Object Modifier: The entry point used when calling Modifier.xxx(). It acts as the root of the chain.
    2. Modifier.Element: The actual functional modifiers (e.g., SizeModifier created by Modifier.size()). Most specific modifiers implement this sub-interface or its descendants (like LayoutModifier or DrawModifier).
    3. CombinedModifier: An internal data structure used to link multiple modifiers together into a chain.