Closed4

Composeの"Tap and press"を読む

mtkw0127mtkw0127

単純なタップ

お馴染みのclickable

Box(
    modifier = Modifier
        .background(Color.Blue)
        .fillMaxSize()
        .clickable { Log.d("@@@", "onClick") }
)

長いタップ

押したタイミングでonClickがcallされ、少し経つとonLongClickがcallされる。

Box(
    modifier = Modifier
        .fillMaxSize()
        .combinedClickable(
            onClick = {
                Log.d("@@@", "onClick")
            },
            onLongClick = {
                Log.d("@@@", "onLongClick")
            },
            onLongClickLabel = "test"
        )
)
mtkw0127mtkw0127

長押しの場合はHapticFeedbackがベストプラクティス

val haptic = LocalHapticFeedback.current
Box(
    modifier = Modifier
        .fillMaxSize()
        .combinedClickable(
            onClick = {
                Log.d("@@@", "onClick")
            },
            onLongClick = {
                Log.d("@@@", "onLongClick")
                haptic.performHapticFeedback(HapticFeedbackType.LongPress)
            },
            onLongClickLabel = "test"
        )
)
mtkw0127mtkw0127

エフェクトなしでclickしたい場合はpointerInputdetectTapGestures

Modifier.clickableは視覚的なエフェクトがかかり、ユーザがタップしたことが分かりやすい感じになっている。ただそのエフェクトが邪魔な時もある。その場合は以下のようにする。

Box(
    modifier = Modifier
        .fillMaxSize()
        .pointerInput(Unit) {
            detectTapGestures {
                Log.d("@@@", "Taped!")
            }
        }
)
mtkw0127mtkw0127

calculateOffsetの計算は自前でやらないといけないがダブルタップした箇所をフォーカスするようなケースの場合、detectTapGestures#onDoubleTapは有用。

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
        }
)
このスクラップは2023/09/29にクローズされました