问题描述
我正在尝试创建如下所示的 UI。我有一个 startDate 和 endDate(例如 1:55am 和 11:35am)。我怎样才能按比例(使用几何阅读器)找到两个日期之间的每小时并像这里所做的那样绘制它们?我在想在某个时候我可能需要使用 seconds 或 timeIntervalSince,但我不太明白如何最好地去做?
到目前为止,我的代码正确地获取了小时数,但我需要根据时间按比例将它们隔开:
我的代码是什么样的:
struct AsleepTimeView: View {
@EnvironmentObject var dataStore: DataStore
static let sleepTimeFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
return formatter
}()
var body: some View {
Color.clear.overlay(
GeometryReader { geometry in
if let mostRecentSleepDay = dataStore.pastSevenSleepDays?.last,let firstSleepSpan = mostRecentSleepDay.sleepSpans.first,let lastSleepSpan = mostRecentSleepDay.sleepSpans.last {
vstack(alignment: .center) {
HStack {
Text("\(firstSleepSpan.startDate,formatter: Self.sleepTimeFormat) ")
.font(.footnote)
Spacer()
Text("\(lastSleepSpan.endDate,formatter: Self.sleepTimeFormat)")
.font(.footnote)
}
HStack(spacing: 3) {
ForEach(dataStore.sleepOrAwakeSpans) { sleepOrAwakeSpan in
RoundedRectangle(cornerRadius: 5)
.frame(width: getWidthForRoundedRectangle(proxy: geometry,spacing: 3,seconds: sleepOrAwakeSpan.seconds,sleepOrAwakeSpans: athlyticDataStore.sleepOrAwakeSpans),height: 10)
.foregroundColor(sleepOrAwakeSpan.asleep == false ? TrackerConstants.scaleLevel5Color : TrackerConstants.scaleLevel8Color)
}
}
HStack {
ForEach(getHoursBetweenTwoDates(startDate: firstSleepSpan.startDate,endDate: lastSleepSpan.endDate).map { Calendar.current.component(.hour,from: $0) },id: \.self) { hour in
HStack {
Text("\(hour)")
.font(.footnote)
Spacer()
}
}
}
HStack {
HStack {
Circle()
.foregroundColor(TrackerConstants.scaleLevel8Color)
.frame(width: 10,height: 10)
Text("Asleep")
.font(.footnote)
}
HStack {
Circle()
.foregroundColor(TrackerConstants.scaleLevel5Color)
.frame(width: 10,height: 10)
Text("Awake")
.font(.footnote)
}
Spacer()
}
}
}
}) // end of overlay
}
//helper
private func getWidthForRoundedRectangle(proxy: GeometryProxy,spacing: Int,seconds: TimeInterval,sleepOrAwakeSpans: [SleepOrAwakeSpan]) -> CGFloat {
let totalSpace = (sleepOrAwakeSpans.count - 1) * spacing
let totalSleepTime = sleepOrAwakeSpans.map { $0.endTime.timeIntervalSince($0.startTime) }.reduce(0,+)
guard totalSleepTime > 0 else { return 0}
let width = (proxy.size.width - CGFloat(totalSpace)) * CGFloat(seconds / totalSleepTime)
return width
}
func datesRange(from: Date,to: Date,component: Calendar.Component) -> [Date] {
// in case of the "from" date is more than "to" date,// it should returns an empty array:
if from > to { return [Date]() }
var tempDate = from
var array = [tempDate]
while tempDate < to {
tempDate = Calendar.current.date(byAdding: component,value: 1,to: tempDate)!
array.append(tempDate)
}
return array
}
func getHoursBetweenTwoDates(startDate: Date,endDate: Date) -> [Date] {
var finalArrayOfHours = [Date]()
guard endDate > startDate else { return finalArrayOfHours }
let arrayOfHours = datesRange(from: startDate,to: endDate,component: .hour)
for date in arrayOfHours {
let hour = date.nearestHour()
finalArrayOfHours.append(hour)
}
return finalArrayOfHours
}
}
extension Date {
func nearestHour() -> Date {
return Date(timeIntervalSinceReferenceDate:
(timeIntervalSinceReferenceDate / 3600.0).rounded(.toNearestOrEven) * 3600.0)
}
}
解决方法
Calendar 类中有一整套方法可以帮助您完成任务。
在我的脑海里,我想说你会做如下的事情:
在循环中,使用 use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Posts\VuePostController;
Route::get('posts',[VuePostController::class,'index']);
Route::get('post/{id}','show']);
Route::post('post','store']);
Route::put('post','store']);
Route::delete('post/{id}','destroy']);
将一个小时一次添加到您的 startDate。如果结果≤ endDate,则使用date(byAdding:to:wrappingComponents:)
获取新计算日期的小时。