Android jetpack compose中的按钮长按监听器
Posted
技术标签:
【中文标题】Android jetpack compose中的按钮长按监听器【英文标题】:Button Long Press Listener in Android jetpack compose 【发布时间】:2021-04-26 08:36:22 【问题描述】:我有一个带有 Button
的 android 可组合 UI。
如何跟踪按钮长按事件?我让它适用于Text
长按,但对于Button
,它不起作用。如果我对按钮应用修饰符,则与下面的方法相同,它不起作用。
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")
,
),
)
【问题讨论】:
我认为你可以使用 LongPressFiredEvent 但我不确定。 【参考方案1】: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】:你可以像下面这样使用combinedClickable
:
Modifier
.combinedClickable(
onClick = ,
onLongClick = ,
)
警告:使用 Compose 1.0.1
,此方法被标记为 @ExperimentalFoundationApi
,因此此答案在未来的版本中可能会过时。
【讨论】:
【参考方案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")
【讨论】:
【参考方案4】:根据documentation
Modifier.pointerInput(Unit)
detectTapGestures(
onPress = /* Called when the gesture starts */ ,
onDoubleTap = /* Called on Double Tap */ ,
onLongPress = /* Called on Long Press */ ,
onTap = /* Called on Tap */
)
【讨论】:
【参考方案5】:5 个月后,由于 API 更改,已接受的答案不起作用。 Button
上的 detectTapGestures()
对我也不起作用(我猜是 .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()
如果有更好的方法,请分享。因为目前的解决方案很丑。
【讨论】:
现在不工作以上是关于Android jetpack compose中的按钮长按监听器的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack Compose 中的文本渐变
android jetpack compose中的“remember”和“mutableState”有啥区别?
Android jetpack compose中的按钮长按监听器