Android jetpack 中的按钮长按监听器组合

时间:2021-01-21 21:00:27

标签: android android-jetpack-compose

我有一个带按钮的 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")
                     })
                ) 

4 个答案:

答案 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()。如果 ButtondetectTapGestures() 对您不起作用,那么这个也不起作用。

第三个私有构造函数不会覆盖您的点击事件。所以我最终只是偷了它并将它放在自定义 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,因此此答案在未来版本中可能会过时。