brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
compose-animationsUse when writing or reviewing Jetpack Compose motion: visibility enter/exit, animating one property toward a target, color or size transitions, multiple properties from one state, switching composable content, or choosing between AnimatedVisibility, animate*AsState, rememberTransition, AnimatedContent, and Crossfade.
Independent GitHub snapshot · Automated classification · Original documentation governs
Pick the smallest API that expresses the motion and its lifecycle.
Animatable only when gestures, interruption, or imperative control require it.AnimatedVisibility removes it after exit. Do not use a fade when unmounting is required.AnimatedContent, render from the content lambda target and choose a
contentKey only when visual identity differs from payload equality. In a
swap between distinct items, keep the target value as the identity (the
default) or key by a stable item ID; do not collapse different items to a
shared presence or branch key. In a review, name any rendered expression that
captures outer target state and
recommend using the lambda target there. If a test must prove transition
identity, check outgoing and incoming content during the overlap; checking
only the settled destination misses a shared-identity bug. Read
AnimatedContent identity for state-holder
details.State in layout or draw block modifiers when it changes at frame rate; route deeper diagnosis to Compose performance.| Need | Prefer |
|---|---|
| Show/hide a subtree with enter/exit semantics | AnimatedVisibility |
| One value follows state | animate*AsState |
| Several values follow one boolean, enum, or sealed state | rememberTransition plus child animations |
| Child size changes | Modifier.animateContentSize() |
| Different composable trees fill one region | AnimatedContent, or Crossfade for the simple case |
| Drag, fling, interruption, or imperative control | Animatable |
Use an AnimationSpec when the default motion is wrong and a distinct label when multiple animations need tooling visibility.
val width by animateDpAsState(
targetValue = if (expanded) 200.dp else 56.dp,
animationSpec = spring(dampingRatio = 0.7f),
label = "fabWidth",
)
For values that must remain synchronized, define them on one transition rather than several independent animate*AsState calls:
val transition = rememberTransition(targetState = phase, label = "phase")
val alpha by transition.animateFloat(label = "alpha") { target ->
if (target == Phase.Visible) 1f else 0f
}
val offset by transition.animateDp(label = "offset") { target ->
if (target == Phase.Visible) 0.dp else 24.dp
}
For animated fills, prefer drawBehind { drawRect(color.value) } over a value-form background when the color updates every frame. For an API ambiguity, start with the official Choose an animation API guide; use rememberInfiniteTransition for repeating cycles and SeekableTransitionState for seekable or test-controlled progress.