remember / mutableStateOf
跨重组保存可观察状态
var x by remember { mutableStateOf(0) }
字段 + setXxx
忘记 remember 导致重置
正文:打开
按 API / XML / 易错点筛选;链回正文锚点。
remember / mutableStateOf跨重组保存可观察状态
var x by remember { mutableStateOf(0) }
字段 + setXxx
忘记 remember 导致重置
正文:打开
rememberSaveable旋转后仍保留简单状态
var s by rememberSaveable { mutableStateOf("") }
onSaveInstanceState
复杂对象需 Saver
正文:打开
viewModel()获取与生命周期绑定的 VM
val vm: X = viewModel()
AAC ViewModel
不要自己 new ViewModel()
正文:打开
collectAsStateWithLifecycle生命周期安全收集 Flow
val ui by flow.collectAsStateWithLifecycle()
observe LiveData
在 Composable 内调用
正文:打开
LaunchedEffect进入组合启动协程,离开或 key 变则取消。收集一次性事件、滚动、聚焦。
LaunchedEffect(vm) { vm.events.collect { … } }
这段 UI 在树上时跑(≠ 单纯 onResume)
key 不稳会循环;业务拉数放 ViewModel.init
正文:打开
rememberCoroutineScope回调里启动协程,离开组合取消。
val scope = rememberCoroutineScope(); onClick = { scope.launch { … } }
setOnClickListener + lifecycleScope
不是进页即跑;体里直接 launch 仍会乱飞
正文:打开
DisposableEffect成对注册 / 反注册。
DisposableEffect(key) { …; onDispose { } }
onStart 注册、onStop 反注册
忘记 onDispose;key 不稳会狂注册
正文:打开
BackHandler接管系统返回,离开组合自动卸。
BackHandler(enabled = dirty) { ask = true }
OnBackPressedCallback
对话框打开时下层仍 enabled
正文:打开
LifecycleResumeEffect对齐前台 / 后台,回前台再刷、埋点。
LifecycleResumeEffect(Unit) { …; onPauseOrDispose { } }
onResume / onPause
组合一直在树上时 LaunchedEffect(Unit) 不重跑
正文:打开
SideEffect组合成功后同步写非 Compose 对象。
SideEffect { analytics.setUserId(id) }
布局完成后再同步外部状态
不要发网络;挂起工作用 LaunchedEffect
正文:打开
NavHost / navigate多页面路由与返回栈
nav.navigate("detail/$id")
nav_graph.xml + NavHostFragment
底栏忘记 popUpTo;不要一页一个 Activity
正文:打开
popUpTo / launchSingleTop切 Tab 不叠栈、登录后洗掉登录页。
navigate("home") { popUpTo(start) { saveState = true }; launchSingleTop = true }
singleTop / CLEAR_TOP / setupWithNavController
Compose 不会自动写这几行,底栏要点一次抄一次
正文:打开
navArgument路径/查询参数声明类型。
composable("detail/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType }))
<argument> / Safe Args / putExtra
特殊字符要 Uri.encode;只传 id 不传整页对象
正文:打开
SavedStateHandle 返回传值详情改完,通知列表刷新。
nav.previousBackStackEntry?.savedStateHandle?.set("needRefresh", true)
setResult / setFragmentResult
必须写 previous,不是 current
正文:打开
navDeepLinkURL / 推送打开指定目的地。
deepLinks = listOf(navDeepLink { uriPattern = "https://…/{id}" })
<deepLink app:uri> + intent-filter
Manifest 仍要声明,和 XML 时代一样
正文:打开
LazyColumn / items惰性列表
LazyColumn { items(list, key=…) { } }
RecyclerView
用 Column 硬塞长列表
正文:打开
PullToRefreshBox下拉触发重新加载,转圈由 isRefreshing 驱动。
PullToRefreshBox(isRefreshing, onRefresh) { LazyColumn(Modifier.fillMaxSize()) }
SwipeRefreshLayout
必须包在列表外面,不要放进 item
正文:打开
PullToRefreshState 自定义指示器用下拉进度画品牌动画,不重写手势。
indicator = { Icon(Modifier.graphicsLayer { rotationZ = state.distanceFraction * 180f }) }
自定义 SwipeRefresh Header
松手后 fraction 回 0,刷新中要改用 Infinite 连转
正文:打开
PagingSource / Pager按页向接口要数据;VM 里 cachedIn 抗旋转。
Pager(PagingConfig(20)) { NewsPagingSource(api) }.flow.cachedIn(viewModelScope)
同一套 Paging 3,RV 用 PagingDataAdapter
页码只来自 params.key;空列表要 nextKey=null
正文:打开
collectAsLazyPagingItemsCompose 列表收集分页,并用 loadState 画三态。
val items = vm.pages.collectAsLazyPagingItems(); items.refresh() / items.retry()
PagingDataAdapter.loadStateFlow
下一页靠滑动;refresh 是整表重来
正文:打开
Modifier.padding/background间距与背景
Modifier.background(…).padding(…)
padding/background 属性
顺序决定结果
正文:打开
Scaffold页面标准壳
Scaffold(topBar=…){ padding -> … }
AppBar+根布局
忽略 innerPadding
正文:打开
AlertDialog状态驱动对话框
if (open) AlertDialog(…)
AlertDialog.Builder
关闭不改状态
正文:打开
OutlinedTextField受控输入框
OutlinedTextField(value, onValueChange)
EditText
缺少 onValueChange
正文:打开
stringResource读字符串资源
Text(stringResource(R.string.x))
@string
写死文案难翻译
正文:打开
MaterialTheme / colorScheme全 App 颜色、字阶、形状入口;业务读令牌。
Text(color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.bodyLarge)
themes.xml / ?attr/colorOnSurface
主色上的字用 onPrimary,不要写死 White
正文:打开
isSystemInDarkTheme读系统深浅;和用户三态合成 darkTheme。
AppTheme(darkTheme = mode.toDark(isSystemInDarkTheme()))
values-night + setDefaultNightMode
边到边后还要改 isAppearanceLightStatusBars
正文:打开
pluralStringResource复数文案;图用 painterResource。
pluralStringResource(R.plurals.item_count, n, n)
@plurals / getQuantityString
VM 里不要 context.getString;UI 读资源 id
正文:打开
contentDescription读屏听到的名字;装饰图传 null。
Icon(Icons.Default.ArrowBack, contentDescription = "返回")
android:contentDescription
图标+文字行用 mergeDescendants,图标侧传 null
正文:打开
dynamicLightColorSchemeAndroid 12+ 按壁纸生成配色。
if (SDK >= 31) dynamicDarkColorScheme(context) else darkScheme
—
始终用 onPrimary,不要假设主色一定够深
正文:打开
remember(keys) / key身份变化时重置局部状态。
remember(userId) { … } 或 key(id) { … }
换业务 id 时清字段
固定 remember 导致串用户数据
正文:打开
Saver / listSaver让复杂对象能 rememberSaveable。
rememberSaveable(stateSaver = …)
自定义 onSaveInstanceState
会话级数据应放 ViewModel
正文:打开
snapshotFlowCompose State 变成 Flow。
snapshotFlow { listState.firstVisibleItemIndex }
滚动监听记位置
收集放 Effect;块内只读 State
正文:打开
combine + stateInVM 多源合成一份热 StateFlow。
combine(…).stateIn(viewModelScope, WhileSubscribed(5_000), …)
MediatorLiveData 合并
界面页优先 WhileSubscribed
正文:打开
mutableStateListOf / Map可观察集合,增删改驱动重组。
val list = remember { mutableStateListOf(...) }
改数据后 notify Adapter
普通 List 原地修改界面不更新
正文:打开
derivedStateOf由其他 State 派生,减少无用重组。
val x by remember { derivedStateOf { ... } }
每次数据变手动重算
依赖非 State 且 key 不对会陈旧
正文:打开
produceState组合内异步结果变成 State。
val v by produceState(initial, key) { value = ... }
回调里 setText
正式业务仍优先 VM
正文:打开
rememberUpdatedState长 Effect 里总用最新回调。
val current by rememberUpdatedState(onEvent)
Compose 特有
LaunchedEffect(Unit) 直接调过期 lambda
正文:打开
LiveData.observeAsState遗留 LiveData 桥成 Compose State。
val v by liveData.observeAsState()
observe(owner)
长期应迁到 Flow
正文:打开
mutableIntStateOf 等基本类型 State,减少装箱。
var n by remember { mutableIntStateOf(0) }
基本类型字段
仍需 remember / Saveable
正文:打开
animate*AsState目标值变了,当前值平滑追过去。
val w by animateDpAsState(if (on) 200.dp else 80.dp, label = "w")
ObjectAnimator / ViewPropertyAnimator
组件进出不要用它,用 AnimatedVisibility
正文:打开
AnimatedVisibility布尔控制一块 UI 进出组合。
AnimatedVisibility(visible, enter = fadeIn(), exit = fadeOut()) { … }
animateLayoutChanges
退出动画未结束不要另开 AsState 改 alpha
正文:打开
AnimatedContent同一槽位按状态换内容并过渡。
AnimatedContent(state, label = "s") { when (it) { … } }
ViewSwitcher / ViewFlipper
lambda 里要用参数 it,不要读外面的最新值
正文:打开
Modifier.animateContentSize子内容变高变宽,容器平滑跟着长。
Column(Modifier.animateContentSize()) { … }
animateLayoutChanges
和 AnimatedVisibility 叠在同一节点会抢尺寸
正文:打开
Modifier.animateItem()Lazy 增删重排时条目自己滑。
items(list, key = { it.id }) { Row(Modifier.animateItem()) }
RecyclerView.ItemAnimator
必须稳定 key;旧 API animateItemPlacement 已过时
正文:打开
rememberInfiniteTransition循环旋转、呼吸灯、骨架闪动。
val inf = rememberInfiniteTransition(label); inf.animateFloat(…)
repeatCount = INFINITE
离开可见性后要卸掉,别在预加载页空转
正文:打开
spring / tween动画规格:弹簧或固定时长。
animationSpec = spring() 或 tween(220, easing = FastOutSlowInEasing)
Interpolator + duration
跟手拖拽用 spring,不要用 tween
正文:打开
updateTransition一个状态同时驱动多个属性。
val t = updateTransition(state, label); t.animateDp { … }
AnimatorSet
只有多属性必须齐步才用
正文:打开
Animatable手势跟手、顺序动画、甩动衰减。
scope.launch { x.animateTo(0f, spring()) }
ValueAnimator
只能在协程里 animateTo;并发会互斥取消
正文:打开
SharedTransitionLayout缩略图飞到详情的共享元素。
Modifier.sharedElement(rememberSharedContentState(key), this)
Activity 共享元素
必须同一 Layout 子树;导航要把 Scope 往下传
正文:打开
Crossfade两个状态交叉淡入,Content 的简化版。
Crossfade(targetState = tab, label = "tab") { … }
—
需要滑入/展开时不要用它
正文:打开