许多可组合项都内置了对点按或点击的支持,并且包含
onClick
lambda。例如,您可以创建一个可点击的 Surface
,
包括所有适合与 Surface 交互的 Material Design 行为:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
但是,点击并不是用户与可组合项互动的唯一方式。当前页面 侧重于涉及单个指针的手势,此时 该指针对于处理该事件并不重要。以下 表格列出了以下类型的手势:
手势 |
说明 |
点按(或点击) |
指针先向下再向上 |
点按两次 |
指针向下,向上,向下,向上 |
长按 |
指针按下,并保持较长时间 |
新闻 |
指针向下移动 |
响应点按或点击操作
clickable
是一个常用的修饰符,可让可组合项对
轻按或点击。此修饰符还添加其他功能,例如支持
鼠标和触控笔悬停,以及可自定义的视觉指示,
已按下。该修饰符响应“点击”而不是
还可通过键盘输入或在
使用无障碍服务
假设在图片网格中,当用户查看某个图片时,该图片会全屏显示 点击它:
您可以通过向网格中的每个项添加 clickable
修饰符来实现这一点
行为:
@Composable private fun ImageGrid(photos: List<Photo>) { var activePhotoId by rememberSaveable { mutableStateOf<Int?>(null) } LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) { items(photos, { it.id }) { photo -> ImageItem( photo, Modifier.clickable { activePhotoId = photo.id } ) } } if (activePhotoId != null) { FullScreenImage( photo = photos.first { it.id == activePhotoId }, onDismiss = { activePhotoId = null } ) } }
clickable
修饰符还会添加其他行为:
interactionSource
和indication
:当 用户点按该可组合项。如需了解如何自定义这些设置,请参阅处理用户 互动页面上。- 允许无障碍服务与元素交互,方法是设置 语义信息。
- 通过允许焦点和按下操作,支持键盘或操纵杆互动
Enter
或方向键中心可进行互动。 - 使元素可悬停,使其能够响应鼠标或触控笔悬停操作 。
长按可显示上下文菜单
combinedClickable
可让您在以下元素中添加点按两次或长按行为:
正常点击行为以外的功能。您可以使用 combinedClickable
来展示
在用户轻触并按住网格图片时触发的上下文菜单:
var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) } val haptics = LocalHapticFeedback.current LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) { items(photos, { it.id }) { photo -> ImageItem( photo, Modifier .combinedClickable( onClick = { activePhotoId = photo.id }, onLongClick = { haptics.performHapticFeedback(HapticFeedbackType.LongPress) contextMenuPhotoId = photo.id }, onLongClickLabel = stringResource(R.string.open_context_menu) ) ) } } if (contextMenuPhotoId != null) { PhotoActionsSheet( photo = photos.first { it.id == contextMenuPhotoId }, onDismissSheet = { contextMenuPhotoId = null } ) }
根据最佳实践,您应在用户
因此,该代码段包含
performHapticFeedback
调用。
点按纱罩以关闭可组合项
在上面的示例中,clickable
和 combinedClickable
添加
功能。它们以直观的方式呈现互动情况
响应悬停操作,并提供焦点、键盘和无障碍功能支持。但是
这种额外行为并不总是可取的。
我们来看看图片详情界面。背景应为半透明 并且用户应该能够点按该背景来关闭详情屏幕:
在这种情况下,背景上不应显示任何可见指示,
互动、不应响应悬停、不可聚焦,并且其
对键盘和无障碍事件的响应不同于
可组合项。您无需尝试调整 clickable
行为,而是可以
降低到较低的抽象级别,并直接使用 pointerInput
修饰符
与 detectTapGestures
方法结合使用:
@OptIn(ExperimentalComposeUiApi::class) @Composable private fun Scrim(onClose: () -> Unit, modifier: Modifier = Modifier) { val strClose = stringResource(R.string.close) Box( modifier // handle pointer input .pointerInput(onClose) { detectTapGestures { onClose() } } // handle accessibility services .semantics(mergeDescendants = true) { contentDescription = strClose onClick { onClose() true } } // handle physical keyboard input .onKeyEvent { if (it.key == Key.Escape) { onClose() true } else { false } } // draw scrim .background(Color.DarkGray.copy(alpha = 0.75f)) ) }
您将作为 pointerInput
修饰符的键传递 onClose
lambda。这个
自动重新执行 lambda,确保调用正确的回调
当用户点按纱罩时触发。
点按两次即可缩放
有时,clickable
和 combinedClickable
提供的信息不足
以正确的方式响应互动。例如,可组合项
需要访问可组合项边界内的互动位置
事件。
我们再来看看图片详情屏幕。最佳做法是 可以通过双击放大图片:
如视频所示,缩放发生在点按位置周围
事件。当我们放大图片的左侧部分时,结果会有所不同
与正确的部分进行比较我们可以结合使用 pointerInput
修饰符
并使用 detectTapGestures
将点按位置整合到我们的
计算方式:
var zoomed by remember { mutableStateOf(false) } var zoomOffset by remember { mutableStateOf(Offset.Zero) } Image( painter = rememberAsyncImagePainter(model = photo.highResUrl), contentDescription = null, modifier = modifier .pointerInput(Unit) { detectTapGestures( onDoubleTap = { tapOffset -> zoomOffset = if (zoomed) Offset.Zero else calculateOffset(tapOffset, size) zoomed = !zoomed } ) } .graphicsLayer { scaleX = if (zoomed) 2f else 1f scaleY = if (zoomed) 2f else 1f translationX = zoomOffset.x translationY = zoomOffset.y } )
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 了解手势
- Compose 中的 Material Design 2
- Kotlin 对 Jetpack Compose 的支持