YO! I am making a clone of Trello in which the BoardScreen displays a row of Lists, each list contains a List of cards. I want to make the card draggable across the lists so that a card remove from one list and gets saved into another.
I have tried many ways and read many articles about drag and drop implementation in jetpack compose but none of them helped me to know that how could I drag an item of a lazy column outside of its parent view and be draggable on the whole screen.
I am attaching the composable of ListItem which contains the LazyColumn of cards.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BoardListItem(
modifier: Modifier = Modifier,
boardList: BoardList,
viewModel: BoardViewModel,
state: CardState,
editableBoardList : BoardList,
onCardCreated : (CardState,BoardList) -> Unit,
) {
Card(
modifier = modifier,
colors = CardDefaults.cardColors(Color.Black),
elevation = CardDefaults.cardElevation(8.dp),
shape = RoundedCornerShape(8.dp)
) {
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 10.dp, end = 10.dp, top = 10.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = boardList.listName,
color = LightBlue,
fontSize = 16.sp
)
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.Default.MoreVert,
contentDescription = "options",
tint = LightBlue,
)
}
if (boardList.cards.isEmpty()) {
Spacer(modifier = Modifier.height(70.dp))
}
else {
val lazyListState = rememberLazyListState()
var draggedDistanceY by remember {
mutableStateOf(0f)
}
var draggedDistanceX by remember {
mutableStateOf(0f)
}
var initiallyDraggedElement by remember { mutableStateOf<LazyListItemInfo?>(null) }
var currentIndexOfDraggedItem by remember { mutableStateOf<Int?>(null) }
LazyColumn(
state = lazyListState,
modifier = Modifier
.pointerInput(Unit) {
detectDragGesturesAfterLongPress(
onDrag = { change, offset ->
change.consume()
draggedDistanceY += offset.y
draggedDistanceX += offset.x
},
onDragStart = { offset ->
lazyListState.layoutInfo.visibleItemsInfo
.firstOrNull { item -> offset.y.toInt() in item.offset..item.offset+200}
?.also {
currentIndexOfDraggedItem = it.index
initiallyDraggedElement = it
}
},
onDragEnd = { },
onDragCancel = { }
)
},
contentPadding = PaddingValues(
top = 20.dp,
end = 15.dp,
start = 10.dp,
bottom = 10.dp
)
) {
items(boardList.cards.size) { index ->
CardItem(
modifier = Modifier
.fillMaxWidth()
.graphicsLayer {
translationY = draggedDistanceY
.takeIf { index == currentIndexOfDraggedItem } ?: 0f
translationX = draggedDistanceX
.takeIf { index == currentIndexOfDraggedItem } ?: 0f
}
.padding(bottom = 10.dp),
card = boardList.cards[index]
)
}
}
}
}
}
Row(
modifier = Modifier
.padding(start = 10.dp, end = 10.dp, bottom = 12.dp),
horizontalArrangement = Arrangement.SpaceAround
) {
if (boardList == editableBoardList && state == CardState.EDIT) {
TextField(
modifier = Modifier
.fillMaxWidth(),
placeholder = {
Text(text = "Card Name", color = Color.Gray)
},
value = viewModel.cardName.value,
onValueChange = {
viewModel.cardName.value = it
},
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = LightBlue
)
)
}else{
Text(
modifier = Modifier
.clickable {
onCardCreated(CardState.EDIT,boardList)
},
text = "+ Add Card",
color = LightBlue,
fontSize = 14.sp
)
Box(modifier = Modifier.fillMaxWidth()) {
Icon(
modifier = Modifier
.size(20.dp)
.align(TopEnd),
painter = painterResource(id = R.drawable.image_icon),
contentDescription = "",
tint = Color.White
)
}
}
}
}
And here is the lazyrow which contains the BoardListItem
LazyRow(
state = lazyListScope,
modifier = Modifier
.padding(top = 20.dp),
contentPadding = PaddingValues(end = 15.dp),
flingBehavior = flingBehavior
) {
items(board.lists.size) { index ->
BoardListItem(
onCardCreated = { cs,boardList ->
cardState = cs
listBeingEdited = boardList
listBeingEdited.isEdited = true
},
state = cardState,
viewModel = viewModel,
modifier = Modifier
.width(listWidth)
.padding(end = 15.dp),
editableBoardList = listBeingEdited,
boardList = board.lists[index]
)
if(index == board.lists.size-1) {
AddList(
modifier = Modifier
.width(width)
.height(height),
state = boardState,
onClick = {
boardState = it
scope.launch {
lazyListScope.animateScrollToItem(index + 1)
}
},
viewModel = viewModel
)
}
}
}
Hope so i was able to explain my problem, any help would be appreciated!