You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:LazyVerticalGrid触摸单元格位置识别及XML代码迁移

如何在Jetpack Compose的LazyVerticalGrid中通过触摸坐标识别单元格位置?

在Jetpack Compose里没有和原生GridView的pointToPosition直接对应的API,但可以借助LazyListState和Compose的布局测量能力实现相同效果。下面是具体的实现方案:

核心思路

给LazyVerticalGrid添加触摸监听获取坐标后,遍历网格的可见项,通过对比坐标与item的布局边界,确定被触摸的单元格位置。

完整代码示例

import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp

@Composable
fun TouchableGrid() {
    // 模拟网格数据
    val gridItems = List(20) { "Item $it" }
    val gridState = rememberLazyGridState()
    // 记录当前触摸的单元格索引
    val touchedPosition = remember { mutableStateOf<Int?>(null) }

    Box(modifier = Modifier.fillMaxSize()) {
        LazyVerticalGrid(
            columns = GridCells.Fixed(3),
            state = gridState,
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(Unit) {
                    detectTapGestures(
                        onPress = { offset ->
                            // 按下时识别触摸位置,对应原代码的parase_Down逻辑
                            touchedPosition.value = findItemPositionByOffset(gridState, offset)
                        },
                        onTap = {
                            // 抬起时的逻辑,对应原代码的parase_Up
                            touchedPosition.value = null
                        },
                        onDrag = { change, _ ->
                            // 拖动时更新触摸位置,对应原代码的parase_Move
                            val currentOffset = change.position
                            touchedPosition.value = findItemPositionByOffset(gridState, currentOffset)
                        }
                    )
                }
        ) {
            items(gridItems.size) { index ->
                Card(
                    modifier = Modifier
                        .size(100.dp)
                        .padding(8.dp)
                ) {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Text(text = gridItems[index])
                    }
                }
            }
        }

        // 可选:显示当前触摸的单元格索引
        touchedPosition.value?.let { position ->
            Text(
                text = "触摸单元格: $position",
                modifier = Modifier.align(Alignment.TopCenter)
            )
        }
    }
}

// 根据触摸坐标查找对应的单元格索引
private fun findItemPositionByOffset(
    gridState: LazyGridState,
    offset: Offset
): Int? {
    // 遍历所有可见的网格项
    for (visibleItem in gridState.layoutInfo.visibleItemsInfo) {
        // 获取当前item的布局边界
        val itemLeft = visibleItem.offset.x
        val itemTop = visibleItem.offset.y
        val itemRight = itemLeft + visibleItem.size.width
        val itemBottom = itemTop + visibleItem.size.height

        // 判断触摸坐标是否在当前item范围内
        if (offset.x in itemLeft..itemRight && offset.y in itemTop..itemBottom) {
            return visibleItem.index
        }
    }
    return null
}

关键说明

  • pointerInput:Compose中处理触摸事件的标准方式,detectTapGestures封装了按下、拖动、抬起等常用触摸动作,对应原生的ACTION_DOWN、ACTION_MOVE、ACTION_UP。
  • LazyGridState.layoutInfo:提供网格的布局详情,包括所有可见项的位置、尺寸和索引,是实现坐标匹配的核心依据。
  • 坐标匹配逻辑:触摸坐标是相对于LazyVerticalGrid本身的,直接与item的布局边界对比即可,无需额外转换全局坐标。

如果需要处理多点触控等复杂场景,可以直接使用awaitPointerEventScope监听原始PointerEvent,获取对应动作类型。

内容的提问来源于stack exchange,提问作者Ayoub Benzahia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:10:26