Table of contents
My app on the Google play store
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.