with one click
with one click
Android/Kotlin 应用崩溃调试方法论。诊断 UI 冻结 + 崩溃、协程架构中的线程安全问题、Compose 悬浮层崩溃以及 ANR 问题。适用于用户报告:应用冻结后崩溃、UI 卡住、ANR、打开对话框/面板时崩溃,或协程密集型代码中原因不明的崩溃。
"Comprehensive evaluation of code solutions. Invoke when user asks '怎么样', '你觉得咋样', '代码如何', '评估一下', '分析一下', '可行吗' about code approaches. Specially optimized for Android Compose/View hybrid projects."
Automatically validates code changes for compliance. **MUST invoke IMMEDIATELY after completing ANY code modification task** to ensure quality, logging, and bug-free delivery.
| name | compose-scrollbar |
| description | Jetpack Compose 可拖拽垂直滚动条的正确实现方式,包含所有已知坑点和修复方案 |
Compose 没有内置的可拖拽滚动条。自定义实现踩过大量坑,此 Skill 记录唯一验证通过的模式。
已有的可复用组件:app/src/main/java/io/legado/app/ui/widget/components/VerticalScrollbar.kt
提供两个重载:
VerticalScrollbar(state: LazyListState, ...) — LazyColumn 用VerticalScrollbar(state: ScrollState, ...) — Column + verticalScroll 用val listState = rememberLazyListState()
Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) { ... }
VerticalScrollbar(
state = listState,
modifier = Modifier.align(Alignment.CenterEnd)
)
}
Box(modifier = Modifier.weight(1f)) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState)
.padding(16.dp)
) { ... }
VerticalScrollbar(
state = scrollState,
modifier = Modifier.align(Alignment.CenterEnd)
)
}
weight(0f) 导致闪退症状:java.lang.IllegalArgumentException: invalid weight; must be greater than zero
原因:用 Column + Spacer 来定位滚动条 thumb,当滚动到边界时 weight 可能为 0。
修复:绝对不要用 weight 定位 thumb。用 Box + offset { IntOffset(0, px) } 代替。
症状:滚动条从不显示,trackHeightPx 始终为 0。
原因:if (trackHeightPx <= 0f) return 跳过了包含 onSizeChanged 的 Box,导致尺寸永远无法被测量。
修复:外层 Box 必须始终渲染(承载 onSizeChanged),只在内部条件绘制 thumb。
症状:拖动滚动条时它来回跳动,无法正常使用。
原因:用 scrollFraction + dragAmount/trackHeightPx 增量计算,scroll 改变 scrollFraction,scrollFraction 改变下一次目标,形成反馈循环。
修复:用 change.position.y / trackHeightPx 做绝对位置映射,手指在顶部=滚到开头,底部=滚到结尾。
mutableFloatStateOf 委托不支持症状:编译错误。
修复:用 mutableStateOf(0f) 代替。
症状:awaitPointerEventScope、awaitFirstDown 等 unresolved。
修复:使用 detectVerticalDragGestures 高级 API,不要用底层 pointer API。
onSizeChanged 必须放在始终渲染的元素上规则:承载 onSizeChanged 的元素不能有任何条件返回包裹它。
onSizeChanged 和 pointerInputoffset { IntOffset(...) } 定位,不用 weightchange.position.y / trackHeightPx),不用增量Box(Modifier.fillMaxSize())modifier 参数(如果还没有)val listState = rememberLazyListState() 或 val scrollState = rememberScrollState()VerticalScrollbar(state, Modifier.align(Alignment.CenterEnd))如果滚动条不出现或行为异常,检查清单:
visible.size < totalItems 或 maxValue > 0)