I'm confused. Based on <this article> and <repo> ...
# compose
s
I'm confused. Based on this article and repo I created a SwipeCard Composable, which works fine on Compose for Desktop, but neither on Android emulator nor on a real phone. What's wrong? And is there an alternative solution for a Tinder-like swipe that works on Android, too? Code inside 🧵
Copy code
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.unit.IntOffset
import kotlin.math.roundToInt

@Composable
fun SwipeCard(
    enabled: Boolean = true,
    onSwipe: (SwipeDirection) -> Unit = {},
    onSwipeEnded: (SwipeDirection) -> Unit = {},
    swipeThreshold: Float = 300f,
    sensitivityFactor: Float = 3f,
    content: @Composable () -> Unit
) {

    val offset = remember { mutableStateOf(0f) }

    val lastDirection = remember { mutableStateOf(SwipeDirection.NONE) }

    Box(
        modifier = Modifier
            .offset { IntOffset(offset.value.roundToInt(), 0) }
            .pointerInput(enabled) {

                if (!enabled)
                    return@pointerInput

                detectHorizontalDragGestures(
                    onDragEnd = {

                        onSwipeEnded(lastDirection.value)

                        offset.value = 0f
                    },
                    onHorizontalDrag = { change, dragAmount ->

                        offset.value += (dragAmount / density) * sensitivityFactor

                        val direction = when {

                            offset.value > swipeThreshold ->
                                SwipeDirection.RIGHT

                            offset.value < -swipeThreshold ->
                                SwipeDirection.LEFT

                            else ->
                                SwipeDirection.NONE
                        }

                        if (lastDirection.value != direction)
                            onSwipe(direction)

                        lastDirection.value = direction

                        if (change.positionChange() != Offset.Zero)
                            change.consume()
                    }
                )
            }
            .graphicsLayer(
                rotationZ = animateFloatAsState(offset.value / 50).value
            )
    ) {
        content()
    }
}

enum class SwipeDirection {

    NONE,
    LEFT,
    RIGHT
}
a
working what is the issue 🤔
🤔 1
s
It does not work for me. 👀
It executes
pointerInput
, but never calls
onHorizontalDrag
Oh, I see why... The sub component also performs a
detectDragGestures
That's no problem for Compose for Desktop, but Android does not like it apparently 🤔
a
not sure I just copy pasted your code working for me
can you try it directly in a activity or so, may be if you are trying inside some complex view and there's some issue with pointerinput and all
👍 1
s
Yes, found it. On Android you't have nested components with drag listeners while this is no problem on Compose for Desktop.
My (cheap) solution is to turn the one off that I don't need.