Detalhamento do modificador por fase

O Jetpack Compose executa modificadores em fases distintas. A seguinte divisão mostra a qual fase os modificadores comuns pertencem e quando os argumentos ou lambdas são avaliados.

Fase 1: fase de composição

Esses modificadores avaliam argumentos de forma síncrona dentro do @Composable corpo. Qualquer estado lido aqui registra uma dependência com o escopo de reinicialização do elemento combinável e aciona uma recomposição completa quando é alterado.

  • Modificadores de dimensão e dimensionamento estáticos:
    • Modifier.size(dp), Modifier.width(dp), Modifier.height(dp)
    • Modifier.fillMaxSize(), Modifier.fillMaxWidth(), Modifier.fillMaxHeight()
    • Modifier.wrapContentSize(), Modifier.wrapContentWidth(), Modifier.wrapContentHeight()
    • Modifier.requiredSize(), Modifier.defaultMinSize()
    • Modifier.aspectRatio(ratio)
    • Modifier.weight(weight) (em RowScope ou ColumnScope)
    • Modifier.width(IntrinsicSize.Min / Max)
    • Modifier.height(IntrinsicSize.Min / Max)
  • Espaçamento estático e encartes:
    • Modifier.padding(all = dp), Modifier.padding(start, top, end, bottom)
    • Modifier.windowInsetsPadding(insets), Modifier.statusBarsPadding()
  • Modificadores visuais de valor direto:
    • Modifier.alpha(float) (lê o estado durante a composição)
    • Modifier.rotate(degrees) (lê o estado durante a composição)
    • Modifier.scale(scaleX, scaleY) (lê o estado durante a composição)
    • Modifier.background(color = Color, shape = Shape)
    • Modifier.border(width, color, shape)
    • Modifier.shadow(elevation, shape)
    • Modifier.clip(shape)
    • Modifier.blur(radius)
  • Modificadores de posição estática:
    • Modifier.offset(x = dp, y = dp) (sobrecarga de valor direto)
    • Modifier.absoluteOffset(x = dp, y = dp)
  • Modificadores combináveis dinâmicos:
    • Modifier.composed { ... } (executa o corpo da fábrica durante a composição)

Fase 2: fase de layout

A fase de layout é dividida em duas subetapas distintas com escopos de invalidação separados:

Etapa 2A: medição

Determina o tamanho (width, height) e as restrições. A leitura de estado aqui aciona a remedição e o reposicionamento:

  • Modifier.layout { measurable, constraints -> ... }: o código antes de layout(w, h) é executado durante a medição.

Etapa 2B: callbacks de posição e layout

Determina a posição da coordenada (x, y). O estado lido aqui aciona apenas o reposicionamento (pulando a medição e a composição):

  • Modifier.offset { IntOffset(x, y) } (sobrecarga de lambda)
  • Modifier.absoluteOffset { IntOffset(x, y) } (sobrecarga de lambda)
  • Modifier.layout { ... layout(w, h) { placeable.place(x, y) } }: código dentro do bloco layout(w, h) { ... }.
  • Modifier.onPlaced { layoutCoordinates -> ... }: invocado depois que as coordenadas principais são determinadas durante o posicionamento.
  • Modifier.onSizeChanged { intSize -> ... }: invocado após a conclusão da medição do layout se o tamanho tiver mudado.
  • Modifier.onGloballyPositioned { layoutCoordinates -> ... }: invocado depois que toda a transmissão de layout da janela é concluída.

Fase 3: fase de exibição

Esses modificadores são executados durante o desenho da tela. A leitura de estado dentro desses blocos ignora a composição e o layout, executando apenas a transmissão de exibição:

  • Modifier.graphicsLayer { ... }:
    • Propriedades atualizadas na função lambda: alpha, translationX, translationY, scaleX, scaleY, rotationX, rotationY, rotationZ, shadowElevation, shape, clip, renderEffect, transformOrigin.
  • Modifier.drawBehind { ... }:
    • Desenha comandos de canvas atrás do conteúdo combinável.
  • Modifier.drawWithContent { ... }:
    • Controla a ordem de desenho com drawContent().
  • Modifier.drawWithCache { ... }:
    • O bloco externo é executado em mudanças de tamanho ou layout para armazenar em cache objetos Path, Paint ou Brush. onDrawBehind ou onDrawWithContent são executados em cada renderização de frame.

Fora do loop de recomposição: modificadores de observação

Alguns modificadores operam fora das três fases de frame para processar acessibilidade, entrada do usuário e observações de ciclo de vida.

Semântica e acessibilidade

Processa propriedades semânticas para serviços de acessibilidade (TalkBack) e testes:

  • Modifier.semantics { ... }
  • Modifier.clearAndSetSemantics { ... }

Entrada, gestos e eventos

Opera fora do pipeline de renderização de frames trifásico, recebendo eventos de movimento do SO e interações do usuário:

  • Modifier.pointerInput(key) { detectTapGestures { ... } } / detectDragGestures / awaitPointerEventScope
  • Modifier.clickable(enabled, onClickLabel) { ... }
  • Modifier.combinedClickable { ... }
  • Modifier.toggleable { ... }
  • Modifier.selectable { ... }
  • Modifier.draggable(...) / Modifier.scrollable(...) / Modifier.draggable2D(...)
  • Modifier.onFocusChanged { focusState -> ... }
  • Modifier.onKeyEvent { keyEvent -> ... }
  • Modifier.onVisibilityChanged { isVisible -> ... }: o callback é invocado quando a visibilidade de um elemento combinável muda após um atraso configurado, em uma corrotina.

Referência rápida: fase de valor x lambda

Ler um valor de estado em uma lambda adia a leitura para uma fase posterior, o que ignora as fases anteriores quando esse estado muda:

Modificador / Padrão Valor direto (composição) Variante lambda (fase adiada) Quando o estado muda
Deslocamento Modifier.offset(x, y) Modifier.offset { IntOffset(x, y) } Layout (posição) (ignora a composição)
Alfa / Opacidade Modifier.alpha(alpha) Modifier.graphicsLayer { this.alpha = alpha } Desenho (pula Composição e layout)
Rotação Modifier.rotate(degrees) Modifier.graphicsLayer { rotationZ = degrees } Desenho (pula Composição e layout)
Escala Modifier.scale(scale) Modifier.graphicsLayer { scaleX = s; scaleY = s } Desenho (pula Composição e layout)
Tradução Modifier.padding(...) Modifier.graphicsLayer { translationX = ... } Desenho (pula Composição e layout)
Cor do plano de fundo Modifier.background(color) Modifier.drawBehind { drawRect(color) } Desenho (pula Composição e layout)
Rolagem / Paralaxe Modifier.offset(scroll.dp) Modifier.offset { IntOffset(0, scroll) } Layout (posição) (ignora a composição)

Mapeamento da interface Modifier.Node

Para modificadores personalizados que usam a API Modifier.Node de alta performance, as fases são mapeadas diretamente para interfaces de capacidade de nó:

Fase Interface Modifier.Node Métodos principais
Layout (Medir e posicionar) LayoutModifierNode measure(measurable, constraints)
Layout (coordenadas globais) GlobalPositionAwareModifierNode onGloballyPositioned(coordinates)
Layout (posição) LayoutAwareModifierNode onRemeasured(size), onPlaced(coordinates)
Desenho DrawModifierNode draw(ContentDrawScope)
Entrada / Ponteiro PointerInputModifierNode onPointerEvent(...), onCancelPointerInput()
Semântica SemanticsModifierNode applySemantics(SemanticsPropertyReceiver)
Foco FocusEventModifierNode onFocusEvent(focusState)