I’m building a SwiftUI view that displays a vertical list of items grouped by date. I want to update the state variable datetimeID
whenever the user scrolls to a new item in the list. Here’s my current implementation:
struct ProductsListView: View {
@State private var datetimeID: Date?
var body: some View {
ZStack {
Color.blue
let calendar = Calendar(identifier: .gregorian)
let startDate = calendar.startOfDay(for: .now)
let endDate = startDate.addingTimeInterval(60*60*24*70)
let interval = 60.0 * 60.0
let array = Array(stride(from: startDate, to: endDate, by: interval))
let dates: [Date: [Date]] = Dictionary(
grouping: array,
by: { calendar.startOfDay(for: $0) }
)
VStack(alignment: .leading, spacing: 3) {
Text("Products Gallery")
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundStyle(.white)
Text("Log: \(datetimeID?.description ?? "nil")")
.foregroundStyle(.white).bold().font(.headline)
ScrollView(.vertical) {
LazyVStack(alignment: .leading, spacing: 2, pinnedViews: [.sectionHeaders]) {
ForEach(dates.keys.sorted(), id: \.self) { date in
Section(header: Text("\(date.description)").opacity(0.4)) {
ForEach(dates[date]?.sorted() ?? [], id: \.self) { time in
let components = calendar.dateComponents([.hour], from: time)
let hour = components.hour!
Rectangle()
.fill(hour % 3 == 0 ? .orange : .yellow)
.frame(width: .infinity, height: 20)
}
}
}
}
.scrollTargetLayout()
}
.foregroundStyle(Color.white)
.scrollTargetBehavior(.viewAligned)
.scrollPosition(id: $datetimeID)
}
.padding()
}
}
}
The datetimeID
is updating when the user scrolls to a new section, which is expected because .scrollTargetLayout()
modifier is added to LazyVStack
. But I want it update when the user scrolls to a new item (Rectangle in the code), so I’ve tried adding it to Rectangle()
but didn't work.
Any help or suggestions would be greatly appreciated.
As suggested by Sweeper in the comment, adding anchor
parameter solves the problem.
.scrollPosition(id: $datetimeID, anchor: .top)
Thanks Sweeper !