[英]How to add drag to custom layout and change the color of the dragged surface in jetpack compose
我正在使用本教程https://danielrampelt.com/blog/jetpack-compose-custom-schedule-layout-part-1/和第 2 部分來繪制自定義時間表。 我怎么想在它里面使用可拖動的,這樣我就可以在 Jetpack Compose 中更改拖動表面的顏色。 我的目標是垂直拖動一個時隙。 這是我的組合 function。我已經放置了可拖動的 function,但我不知道如何實現它。 現在我的屏幕死機了,我無法垂直滾動。
@Composable
fun DynamicSchedule(
viewModel: CalenderViewModel,
modifier: Modifier = Modifier,
appointmentContent: @Composable (appointment: Appointment) -> Unit = {
ScheduleCard(
appointment = it
)
},
minDate: LocalDate,
maxDate: LocalDate,
dayWidth: Dp,
hourHeight: Dp
) {
val numDays = ChronoUnit.DAYS.between(minDate, maxDate).toInt() + 1
val dividerColor = if (MaterialTheme.colors.isLight) Color.LightGray else Color.DarkGray
var offsetY by remember { mutableStateOf(0f) }
Layout(
content = {
viewModel.state.value.appointmentList.sortedBy { it.startDate }
.forEach { appointment ->
Box(modifier = Modifier.appointmentData(appointment)) {
appointmentContent(appointment)
}
}
},
modifier = modifier
.drawBehind {
repeat(23) {
drawLine(
dividerColor,
start = Offset(0f, (it + 1) * hourHeight.toPx()),
end = Offset(size.width, (it + 1) * hourHeight.toPx()),
strokeWidth = 1.dp.toPx()
)
}
repeat(numDays - 1) {
drawLine(
dividerColor,
start = Offset((it + 1) * dayWidth.toPx(), 0f),
end = Offset((it + 1) * dayWidth.toPx(), size.height),
strokeWidth = 1.dp.toPx()
)
}
}
.pointerInput(Unit) {
detectTapGestures {
val x = it.x.toDp()
val y = it.y.toDp()
val time = y.value.toInt() / hourHeight.value
val date = (x.value.toInt() / dayWidth.value)
println("X: $x, Y: $y")
println("Day: $date, Time: $time")
}
}
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
offsetY += delta
println("Delta: $offsetY")
}
),
) { measurables, constraints ->
println("i got recomposed ======== ")
val height = hourHeight.roundToPx() * 24
val width = dayWidth.roundToPx() * numDays
val placeablesWithAppointment = measurables.map { measurable ->
val appointment = measurable.parentData as Appointment
val appointmentDurationInMinutes =
ChronoUnit.MINUTES.between(
appointment.startDate.time.toJavaLocalTime(),
appointment.endDate.time.toJavaLocalTime()
)
val appointmentHeight =
((appointmentDurationInMinutes / 60f) * hourHeight.toPx()).roundToInt()
val placeable = measurable.measure(
constraints.copy(
minWidth = dayWidth.roundToPx(),
maxWidth = dayWidth.roundToPx(),
minHeight = appointmentHeight,
maxHeight = appointmentHeight
)
)
Pair(placeable, appointment)
}
layout(width, height) {
placeablesWithAppointment.forEach { (placeable, appointment) ->
//appointment time - midnight
val appointmentOffsetMinutes =
ChronoUnit.MINUTES.between(
LocalTime.MIN,
appointment.startDate.time.toJavaLocalTime()
)
val appointmentY =
((appointmentOffsetMinutes / 60f) * hourHeight.toPx()).roundToInt()
val appointmentOffsetDays =
ChronoUnit.DAYS.between(
minDate,
appointment.startDate.date.toJavaLocalDate()
).toInt()
val appointmentX = appointmentOffsetDays * dayWidth.roundToPx()
placeable.place(appointmentX, appointmentY)
}
}
}
}
這里有很多地方出了問題。 首先, draggable
是在Layout
上注冊的,而不是單獨的placeable
布局。 如果你想完成這項工作,你需要檢測拖動布局並相應地放置它,它看起來像這樣:
val touch = remember { mutableStateOf(Offset(0)) }
Box {
...
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, dragAmount ->
change.consumeAllChanges()
touch.value += dragAmount
})
}
...
}
layout(width, height) {
placeablesWithAppointment.forEach { (placeable, appointment) ->
...
placeable.place(appointmentX, appointmentY + touch.value)
...
}
但這樣做的問題是您需要檢測拖動開始的可放置布局。 這只會使您的結構和代碼復雜化。
也就是說,這應該可以通過更簡單的方式實現:
LazyColumn(appointments) {
var draggedBox by remember { mutableStateOf(-1L) }
var draggedOffset by remember { mutableStateOf(-1L) }
var draggedX by remember { mutableStateOf(-1L) }
var draggedY by remember { mutableStateOf(-1L) }
// This should be the tricky part as you might notice a snap after every drag
shuffleList(draggedBox, draggedY, draggedOffset)
Box(modifier = modifier
.onGloballyPositioned {
position = it.localToWindow(Offset.Zero)
}
.offset { // update offsets to show the drag }
.pointerInput(Unit) {
// updated state variables on drag
}) {
compose()
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.