我试图在android compose中使用自定义布局构建自定义日程表。我正在使用一个 Package 器对象来处理事件的数据。每个事件都有一个开始和结束LocalDateTime。当事件不冲突时,代码工作正常,但我需要一种方法来并排显示多个事件。你有什么主意吗?
可组合代码。
@Composable
fun BasicSchedule(
bookings: List<Booking> = mainViewModel.listOfBookings,
modifier: Modifier,
currentSelectedDay: LocalDate = mainViewModel.currentSelectedDay,
hourHeight: Dp = 64.dp,
) {
val dividerColor = if (MaterialTheme.colors.isLight) Color.LightGray else Color.DarkGray
var height = 0
Layout(content = {
bookings.sortedBy(Booking::startTimestamp).forEach { booking ->
if (mainViewModel.currentSelectedDay == booking.startTimestamp.toJavaLocalDateTime()
.toLocalDate()
) {
Box(modifier = Modifier.eventData(booking)) {
BookingViewComposable(booking = booking)
}
}
}
}, modifier = modifier
.fillMaxSize()
.drawBehind {
repeat(23) {
drawLine(
dividerColor,
start = Offset(0f, (it + 1) * hourHeight.toPx()),
end = Offset(size.width, (it + 1) * hourHeight.toPx()),
strokeWidth = 1.dp.toPx()
)
}
}
.pointerInput(Unit) {
detectTapGestures(onLongPress = { offset ->
mainViewModel.newBookingStartTime = offset.y
.div(height / 24)
.roundToInt()
mainViewModel.createNewBookingDialogOpen = true
})
}) { measureables, constraints ->
height = hourHeight.roundToPx() * 24
val placeablesWithEvents = measureables.map { measurable ->
val booking = measurable.parentData as Booking
val eventDurationMinutes = ChronoUnit.MINUTES.between(
booking.startTimestamp.toJavaLocalDateTime(),
booking.endTimestamp.toJavaLocalDateTime()
)
val eventHeight = ((eventDurationMinutes / 60f) * hourHeight.toPx()).roundToInt()
val placeable = measurable.measure(Constraints.fixed(constraints.maxWidth - 30, eventHeight))
Pair(placeable, booking)
}
layout(constraints.maxWidth, height) {
placeablesWithEvents.forEach { (placeable, booking) ->
val eventOffsetMinutes = ChronoUnit.MINUTES.between(
LocalTime.MIN, booking.startTimestamp.toJavaLocalDateTime()
)
val eventY = ((eventOffsetMinutes / 60f) * hourHeight.toPx()).roundToInt()
val eventX = 0
placeable.place(eventX, eventY)
}
}
}
}
how it isHow it should be
你有什么建议吗?
我尝试将LocalDateTime对象相互比较,这是可能的,但我不知道如何使用多个DateTime。
1条答案
按热度按时间fbcarpbf1#
要为每个广义边缘情况正确地堆叠事件将需要复杂的实现,因此这里是一个“简化”的实现(在引号中,因为这个问题的解决方案仍然是不平凡的),对于没有太多重叠事件的情况,它工作得足够好。这种简化的实现方式不均等地分布宽度,并且在宽度重新分布将是可能的一些边缘情况下,简单地让最后一个元素采用一些额外的宽度。
首先,我创建了一个帮助函数来遍历类图数据结构,因为下面的代码以各种方式使用了它几次。它返回一个
Sequence
,它可以对子图/子树进行广度优先或深度优先遍历,并按访问顺序生成节点。在实现中,我只使用了breath-first遍历,但我也在遍历函数中保留了深度优先模式。对于数据结构,我使用了一个
Node
类,它可以保存一个元素,知道它自己在图中的深度,知道它所在的图的总深度,并且可以保存对上一个和下一个节点的引用。我还在代码中保留了
visualDebug
字段,您可以在上面的代码中看到。此调试信息显示哪些元素(事件)受算法不同部分的影响。现在,代码只是根据下面描述的情况将visualDebug
设置为数字1-4,标记为(1.)-(4.),但如果您想探索算法如何工作,您可以在算法代码中的各个步骤中将自己的调试信息添加到该字段。您可以通过更改本文末尾的演示代码中的showVisualDebug
和this UI should show up的值来启用或禁用这些额外的调试信息。我实现的简化算法如下:
factory
函数,将元素、开始权重、结束权重和重叠计数传递给调用。factory
函数负责创建应该返回的结果而不是节点。我还定义了一个
Booking
类和一个EventData
类来创建一个小的用法演示。这是在调用站点使用它的方式:
这就是在创建布局时如何使用事件数据
完整代码
将下面的整个代码复制到一个空的Kotlin文件中,在IDE中打开它,然后选中“编写预览”窗口。This UI should show up。
您还可以从主
Activity
调用OverlappingScheduleUI
组合程序来运行示例代码。