A quick example of how to model complex state in Jetpack compose

Rmag Breaking News

Table of contents

TLDR(Too long didn’t read)
Introduction
Real example
The state modeling

My app on the Google play store

The app

TLDR(Too long didn’t read)

Basically to model any sort of complex Jetpack Compose state do this:

@Composable
fun rememberDraggableActions():ModViewDragState{
return remember {ModViewDragState()}
}

@Stable
class ModViewDragState(){
// all the complex state goes in here
}

Then you can use rememberDraggableActions() just like a normal remember function:

@Composable
fun TestingComplexState(){
val state = rememberDraggableActions()
//all complex state can now be accessed through state

}

Introduction

This blog post is not going to be an in-depth analysis of every little section of code. Instead, it will act as a simple visual demonstration and example on a alternative way to model compose state

Real example

This is my code before the state refactor:

@Composable
fun DraggableText(
setDragging🙁Boolean)->Unit
){
var offsetX = remember { mutableStateOf(0f) }
val draggableState = rememberDraggableState { delta ->
if (offsetX.value >= 300f){
offsetX.value += delta/10
}
else if (offsetX.value <= 300f){
offsetX.value += delta/10
}
else{
offsetX.value += delta
}

}
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.Blue)
.draggable(
orientation = Orientation.Horizontal,
onDragStopped = {
draggableState.drag(MutatePriority.PreventUserInput) {
Animatable(offsetX.value).animateTo(
targetValue = 0f,
tween(durationMillis = 300)
) {
dragBy(value offsetX.value)
}
}
},

enabled = true,
state = draggableState
)
){

CardDemo(
offsetX.value,
setDragging={newValue ->setDragging(newValue)}
)

}

}

after the state refactor:

@Composable
fun DraggableText(
setDragging🙁Boolean)->Unit
){
val state = rememberDraggableActions()
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.Blue)
.draggable(
orientation = Orientation.Horizontal,
onDragStopped = {
state.resetOffset()
},

enabled = true,
state = state.draggableState
)
){
CardDemo(
state.offset.value,
setDragging={newValue ->setDragging(newValue)}
)
}

}

Which as you can see is a lot easier to read and just overall cleaner

The state modeling

All I did was just put all the complex state dealing with the draggable into a class marked with the Stable annotation(allowing compose to skip recomposition if needed).

@Stable
class ModViewDragState(){
val offset: State<Float> get() = offsetX
private var offsetX = mutableStateOf(0f)

val draggableState = DraggableState { delta ->
if (offsetX.value >= 300f){
offsetX.value += delta/5
}
else if (offsetX.value <= 300f){
offsetX.value += delta/5
}
else{
offsetX.value += delta
}

}

suspend fun resetOffset(){
draggableState.drag(MutatePriority.PreventUserInput) {
Animatable(offsetX.value).animateTo(
targetValue = 0f,
tween(durationMillis = 300)
) {
dragBy(value offsetX.value)
}
}
}

}

Conclusion

Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Leave a Reply

Your email address will not be published. Required fields are marked *