簡體   English   中英

如何在自定義布局中添加拖動並更改 Jetpack Compose 中拖動表面的顏色

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM