Reputation: 13367
Recently I just crush with a wall while developing a feature in one of my applications which is using 100% compose!. I'm trying to achieve a Vertical Nested Scroll View. My case is that I'm doing a view to edit/create workouts. These are split in different sets which has a list of exercises inside.
The idea is to have a list of Cards which has a list of items (exercises) inside (Which can be moved using Drag&Drop).
When I try to build the view it gave me the next error:
java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like ScrollableContainer and LazyColumn is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().
I understand that its not supported, what I'm asking if is there is any kind of workaround I could do. The code looks like:
LazyColumn(Modifier.fillMaxSize()) {
itemsIndexed(workout.workoutSets) { setIndex, workoutSet ->
//State that contains the re-order drag & drop and calls the original list to be modified in my VM
val state: ReorderableState = rememberReorderState(onMove = { from, to ->
Grove.e { "Moving from $from to $to" }
if (to <= workoutSet.exercises.lastIndex) {
onExerciseMoved(setIndex, from, to)
}
})
LazyColumn(
state = state.listState,
modifier = Modifier
.fillMaxWidth()
.reorderable(state) //Modifier that allows the drad&drop in this container
) {
itemsIndexed(items = workoutSet.exercises, itemContent = { index, item ->
Box(
Modifier
.fillMaxWidth()
.draggedItem(state.offset.takeIf { state.index == index }) //The dragged item modifier
.scale(if (state.index == null || state.index == index) 1f else .9f)
) {
CreatorExerciseItemRow(
onExerciseClick = { onExerciseClick(item) },
execution = item
)
}
})
}
}
}
You can find the Drag & Drop code that I'm using from the library (not mine) here.
Finally to make you an idea of what I want to achieve. The screen looks like:
The idea is that I can long-press the exercises and drag & drop them on their individual cards. But at the same time allowing the screen to get higher and scroll vertically if needed. Right now I have it working just replacing the first LazyColumn
from code above for a repeat/foreach
. However has soon has my list grows the view gets hide.
Upvotes: 1
Views: 5190
Reputation: 88457
I'm afraid it's not possible.
As I understand, it's enough for you to restrict items to be moved between different sets.
You can take source code of ComposeReorderable
and apply needed changes for your task. There's not much code(which I like compose for), so it shouldn't be too hard. Maybe even submit a pull request when you're done, because such functionality may be useful for others.
Upvotes: 1
Reputation: 24044
You can use a single plain list and draw the content based on the type.
First you should transform your data in a single plain list (this is, of course, a pseudo code).
val plainList = mutableListOf<Any>()
worksets.forEach {
plainList.add(it)
it.exercises.forEach{
plainList.add(it)
}
}
and then, in your LazyColumn
you draw the item based on the item type.
LazyColumn(Modifier.fillMaxSize()) {
items(plainList) { item ->
when (item) {
is Workset -> WorkSetHeaderItem(item)
is Exercise -> ExerciseItem(item)
}
}
}
Upvotes: 0