Search code examples
androidkotlinandroid-jetpack-compose

How do I store a mutable variable as part of an object in Compose?


I am attempting to create a track-pad class to use with Compose. The class currently has 2 methods one to initialize the track-pad and one for the cursor.(The cursor needs to able to move independently of the track-pad so I cannot define them in the same function). However I have no way of transferring the information of where the cursor needs to be from the track-pad to the cursor.

I have attempted to define variables as part of the constructor as well as part of an initalizer block, however the compiler throws an error as neither can be marked as composable:

This annotation is not applicable to target 'constructor'

This is my code:

class Trackpad
    @Composable
    constructor(
        var xofs: unit = remember{mutableFloatStateOf(0f)},
        var yofs: unit = remember { mutableFloatStateOf(0f) }
    )
{
    @Composable
    fun Pad(modifier: Modifier){

        Surface(
            modifier = modifier
                .fillMaxWidth()
                .pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()
                        xofs += dragAmount.x * 3
                        yofs += dragAmount.y * 3
                    }
                },
            color = Color.Cyan
        ){}
    }
    @Composable
    fun Cursor() {
        var mxof by remember { mutableFloatStateOf( xofs)}
        var myof by remember { mutableFloatStateOf( yofs)}
        Text(text = "Will be curser", modifier = Modifier

            .offset() { IntOffset(xofs.roundToInt(), yofs.roundToInt()) }
        )
    }
}

I have also tried using normal floats in the constructor, however it results in the cursor not moving.


Solution

  • It looks like you wanna share the xofs and yofs between the pad and the cursor. To achieve this you can define a state holder class TrackpadState.

    import androidx.compose.runtime.*
    
    class TrackpadState {
        var xOffset by mutableStateOf(0f)
            private set
        var yOffset by mutableStateOf(0f)
            private set
    
        fun updateOffset(deltaX: Float, deltaY: Float) {
            xOffset += deltaX * 3
            yOffset += deltaY * 3
        }
    }
    

    Then we can pass the state into Pad and Cursor composables.

    val trackpadState = remember { TrackpadState() }
    
    @Composable
        fun Pad(state: TrackpadState, modifier: Modifier = Modifier) {
            Surface(
                modifier = modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    .background(Color.Cyan)
                    .pointerInput(Unit) {
                        detectDragGestures { change, dragAmount ->
                            change.consume()
                            state.updateOffset(dragAmount.x, dragAmount.y)
                        }
                    }
            ) {}
        }
    
        @Composable
        fun Cursor(state: TrackpadState, modifier: Modifier = Modifier) {
            Box(
                modifier = modifier
                    .offset { IntOffset(state.xOffset.roundToInt(), state.yOffset.roundToInt()) }
                    .size(20.dp)
                    .background(Color.Red)
            )
        }