我有一个垂直的Column
,它有两个子元素:
- Accompanist提供的
Pager
组件,用于显示Text
。 Canvas
组件,绘制两个圆弧和一个圆形。
它们的顺序与此处描述的相同。我希望Text
始终呈现在Canvas
后面。
实现细节
Canvas
组件有一个Modifier.pointerInteropFilter
,处理MotionEvent.ACTION_DOWN
和MotionEvent.ACTION_MOVE
事件。如果事件不在圆弧的10%距离内,则会被忽略,并返回false
。
我的理解是返回false
将表示事件未被消耗,因此将传递给Pager
处理 - 但事实并非如此。一旦Modifier.pointerInteropFilter
被注册,无论返回true
还是false
,Pager
都永远不会接收到输入事件。
布局
以下是我当前实现的简化版本,为了简洁起见。我有一个Column
,先呈现Pager
,然后是Canvas
。
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
// The Pager should always be rendered behind the Canvas. This is to
// prevent the Text from rending on top when being dragged.
HorizontalPager(
state = rememberPagerState(pageCount = 8000, initialPage = 4000)
) { page ->
Text(
modifier = Modifier.fillMaxWidth(),
text = "25:00",
textAlign = TextAlign.Center,
fontSize = 60.sp
)
}
}
var progress by remember { mutableStateOf(0.25f) }
ArcSeekBar(progress, false) { change ->
progress = change
}
在这个例子中,我已经硬编码指针
pointerInteropFilter
始终返回false,假设它不会消耗/阻塞事件,使其能够通过到Pager
。@Composable
fun ArcSeekBar(progress: Float, interaction: Boolean, changed: (Float) -> Unit) {
val sweepAngle = 270.0f
var width: Int by remember { mutableStateOf(0) }
var height: Int by remember { mutableStateOf(0) }
Canvas(
modifier = Modifier
.fillMaxSize()
.aspectRatio(1.0f)
.onSizeChanged {
width = it.width
height = it.height
}
.pointerInteropFilter {
// Reduced for brevity, but whatever the function returns
// the Pager composable behind it will never receive input events.
false
},
) {
// Omitted for brevity, draw two arcs and a circle
}
}
参考一下,我的布局产生了以下结果: