본문 바로가기

ANDROID/Jetpack

[Android/Jetpack Compose] 컴포즈에서 터치 이벤트를 처리할 때의 유의점

Jetpack Compose 아이템의 더블탭 이벤트에 따라 애니메이션을 수행하는 개발을 진행중에 있었다. 

 

이벤트 처리도 손쉽게 Modifier로 마무리 됐구나 생각한 찰나, 애니메이션이 의도대로 재생되지 않았고 

 

긴 추적 끝에 터치 이벤트를 통해 전달된 대상 state가 재생을 필요하는 UI의 state와 일치하지 않는 것을 확인했다. 

 

아래는 doubleTap 제스처를 트래킹하는 Android Developers page 스니펫인데, pointerInput의 parameter를 Unit으로 운영하는 걸 확인할 수 있다.

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
        }
)

여기에 원인이 있었는데, 위와 같은 구조가 아닌 람다를 사용해 상위 Composable로 넘겨주는 경우에는 pointerInput의 parameter를 지정해주어야만 했다.

 

아래와 같이 더블탭 수행시 호출하고자 하는 람다를 pointerInput에 parameter로 설정하고 나면, 상위 Composable에서 수행하고자 하는 작업을 기대대로 수행할 수 있게 된다.

 

(이는 List type 같은 여러개의 Composable 내 이벤트를 처리할 때 더 유의해야 하는 작업이겠다.)

data class SomeState(val imageUrl: String)

@Composable
fun ImageMediumUi(
    state: SomeState,
    onDoubleTap: () -> Unit,
) {
    AsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(state.imageUrl)
            .crossfade(true)
            .build(),
        contentDescription = null,
        modifier = Modifier
            .aspectRatio(state.ratio)
            .clip(RoundedCornerShape(4.dp))
            .fillMaxWidth()
            .pointerInput(onDoubleTap) {
                detectTapGestures(
                    onDoubleTap = { onDoubleTap.invoke() }
                )
            },
    )
}

 

https://developer.android.com/jetpack/compose/touch-input/pointer-input/tap-and-press

 

Tap and press  |  Jetpack Compose  |  Android Developers

Tap and press Stay organized with collections Save and categorize content based on your preferences. Many composables have built-in support for taps or clicks and include an onClick lambda. For example, you can create a clickable Surface that includes all

developer.android.com