我有一个带按钮的 Android 可组合用户界面。 如何跟踪按钮长按事件?我让它为“文本”长按工作,但对于按钮它不起作用。如果我将修饰符应用于按钮,则如下所示,它不起作用。
Text(
text = view.text,
fontSize = view.textFontSize.toInt().sp,
fontWeight = FontWeight(view.textFontWeight.toInt()),
color = Color(android.graphics.Color.parseColor(view.textColor)),
modifier = Modifier.clickable(onClick = {
println("Single Click")
}, onLongClick = {
println("Long Click")
}, onDoubleClick = {
println("Double Tap")
})
)
答案 0 :(得分:3)
处理此问题的最佳方法是推出您自己的 Button
。材质 Button
基本上只是一个 Surface
和一个 Row
。添加您自己的 Modifier.clickable
不起作用的原因是因为已经设置了。
因此,如果您想添加 onLongPress
等,您可以复制/粘贴默认实现并传入这些 lambda。
@Composable
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
onLongClick: (() -> Unit)? = null,
onDoubleClick: (() -> Unit)? = null,
enabled: Boolean = true,
interactionState: InteractionState = remember { InteractionState() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
) {
val contentColor by colors.contentColor(enabled)
Surface(
shape = shape,
color = colors.backgroundColor(enabled).value,
contentColor = contentColor.copy(alpha = 1f),
border = border,
elevation = elevation?.elevation(enabled, interactionState)?.value ?: 0.dp,
modifier = modifier.combinedClickable(
onClick = onClick,
onDoubleClick = onDoubleClick,
onLongClick = onLongClick,
enabled = enabled,
role = Role.Button,
interactionState = interactionState,
indication = null
)
) {
Providers(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(
value = MaterialTheme.typography.button
) {
Row(
Modifier
.defaultMinSizeConstraints(
minWidth = ButtonDefaults.MinWidth,
minHeight = ButtonDefaults.MinHeight
)
.indication(interactionState, rememberRipple())
.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
}
}
用法:
Button(
onClick = {},
onLongClick = {},
onDoubleClick = {}
) {
Text(text = "I'm a button")
}
答案 1 :(得分:3)
https://developer.android.com/jetpack/compose/gestures 也可以使用。
例如:
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.gestures.detectTapGestures
modifier = Modifier
.weight(2f)
.pointerInput(Unit){
detectTapGestures(
onLongPress = {
// perform some action here..
}
)
答案 2 :(得分:0)
5 个月后,由于 API 更改,已接受的答案不起作用。 detectTapGestures()
上的 Button
对我也不起作用(我猜 .clickable()
抢走了活动?)。
Surface 现在有两个公共构造函数。第一个不可点击并明确将 .pointerInput(Unit)
覆盖为空
Surface(
...
clickAndSemanticsModifier = Modifier
.semantics(mergeDescendants = false) {}
.pointerInput(Unit) { detectTapGestures { } }
)
第二个(由 Button
使用)可点击并明确设置 Modifier.clickable()
。如果 Button
和 detectTapGestures()
对您不起作用,那么这个也不起作用。
第三个私有构造函数不会覆盖您的点击事件。所以我最终只是偷了它并将它放在自定义 LongPressButton 旁边。
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun LongPressButton(
modifier: Modifier = Modifier,
onClick: () -> Unit = {},
onLongPress: () -> Unit = {},
onDoubleClick: () -> Unit = {},
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
) {
val contentColor by colors.contentColor(enabled)
Surface(
modifier = modifier,
shape = shape,
color = colors.backgroundColor(enabled).value,
contentColor = contentColor.copy(alpha = 1f),
border = border,
elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
clickAndSemanticsModifier = Modifier.combinedClickable(
interactionSource = interactionSource,
indication = rememberRipple(),
enabled = enabled,
role = Role.Button,
onClick = onClick,
onDoubleClick = onDoubleClick,
onLongClick = onLongPress,
)
) {
CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(
value = MaterialTheme.typography.button
) {
Row(
Modifier
.defaultMinSize(
minWidth = ButtonDefaults.MinWidth,
minHeight = ButtonDefaults.MinHeight
)
.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content
)
}
}
}
}
@Composable
private fun Surface(
modifier: Modifier,
shape: Shape,
color: Color,
contentColor: Color,
border: BorderStroke?,
elevation: Dp,
clickAndSemanticsModifier: Modifier,
content: @Composable () -> Unit
) {
val elevationOverlay = LocalElevationOverlay.current
val absoluteElevation = LocalAbsoluteElevation.current + elevation
val backgroundColor = if (color == MaterialTheme.colors.surface && elevationOverlay != null) {
elevationOverlay.apply(color, absoluteElevation)
} else {
color
}
CompositionLocalProvider(
LocalContentColor provides contentColor,
LocalAbsoluteElevation provides absoluteElevation
) {
Box(
modifier
.shadow(elevation, shape, clip = false)
.then(if (border != null) Modifier.border(border, shape) else Modifier)
.background(
color = backgroundColor,
shape = shape
)
.clip(shape)
.then(clickAndSemanticsModifier),
propagateMinConstraints = true
) {
content()
}
}
}
如果有更好的方法,请分享。因为目前的解决方案很难看。
答案 3 :(得分:0)
您可以像下面这样使用 combinedClickable
:
Modifier
.combinedClickable(
onClick = { },
onLongClick = { },
)
警告:在 Compose 1.0.1
中,此方法被标记为 @ExperimentalFoundationApi
,因此此答案在未来版本中可能会过时。