Home > Back-end >  Update remembered value using arguments
Update remembered value using arguments

Time:02-23

I have a Composable in which a remembered value (an offset) needs to be updated both by the Composable itself and also from the calling side (using the Composable's arguments) -- how can I achieve this?

In particular, I have the following piece of code. The value I'm talking about is the offset in NavigableBox: I need to both be able to control it by dragging the box and by setting it manually using the value from OffsetInputField which is passed as an argument.

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Surface {
                Box {
                    var boxOffset by remember { mutableStateOf(Offset.Zero) }

                    NavigableBox(boxOffset)
                    OffsetInputField { offset ->
                        offset.toFloat().let { boxOffset = Offset(it, it) }
                    }
                }
            }
        }
    }
}

@Composable
fun OffsetInputField(onInput: (String) -> Unit) {
    var value by remember { mutableStateOf("") }

    TextField(
        value = value,
        onValueChange = { value = it },
        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
        keyboardActions = KeyboardActions(onGo = { onInput(value) })
    )
}

@Composable
fun NavigableBox(initOffset: Offset) {
    var offset by remember(initOffset) { mutableStateOf(initOffset) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) { detectTransformGestures { _, pan, _, _ -> offset  = pan } }
    ) {
        Box(modifier = Modifier
            .size(100.dp)
            .offset { IntOffset(offset.x.roundToInt(), offset.y.roundToInt()) }
            .background(Color.Blue)
        )
    }
}

In the current implementation the dragging works fine until a new value is passed as OffsetInputField's input -- then the box stops responding to dragging. I assume it is because the MutableState object containing the offset changes when gets recalculated and the box doesn't observe it anymore.

I already tried using unidirectional data flow in NavigableBox (passing offset value and onOffsetChange lambda to it, but then dragging doesn't work as expected: the box just jiggles around its initial position, returning back to it when the gesture stops.

In case anyone interested, I'm developing an app where the draggable box is a map, and the text field is used for searching objects on it: the map is moved to be centered on an object entered.

CodePudding user response:

pointerInput captures all the state variables used inside. With new initOffset you're creating a new mutable state, but pointerInput keeps updating the old reference.

You need to restart it by passing the same value(s) to key:

pointerInput(initOffset) { /*...*/ }
  • Related