Смещение содержимого в ScrollView SwiftUI
Я создал простой горизонтальный календарь с помощью SwiftUI, и он отлично работает. Но я хочу, чтобы он автоматически прокручивался до текущей даты при запуске приложения. Как я могу это сделать? Я предполагаю, что мне следует использовать GeometryReader, чтобы получить позицию кадра с текущей датой и установить смещение на ее основе, но ScrollView не имеет модификатора смещения содержимого. Я знаю, что в iOS 14 теперь есть ScrollViewReader, но как насчет iOS 13?
struct MainCalendar: View {
@Environment(\.calendar) var calendar
@State private var month = Date()
@State private var selectedDate: Date = Date()
var body: some View {
VStack(spacing: 30) {
MonthAndYearView(date: $month)
WeekDaysView(date: month)
}
.padding(.vertical)
}
}
struct MonthAndYearView: View {
@Environment(\.calendar) var calendar
private let formatter = DateFormatter.monthAndYear
@Binding var date: Date
var body: some View {
HStack(spacing: 20) {
Button(action: {
self.date = calendar.date(byAdding: .month, value: -1, to: date)!
}, label: {
Image(systemName: "chevron.left")
})
Text(formatter.string(from: date))
.font(.system(size: 18, weight: .semibold))
Button(action: {
self.date = calendar.date(byAdding: .month, value: 1, to: date)!
}, label: {
Image(systemName: "chevron.right")
})
}
}
}
struct WeekDaysView: View {
@Environment(\.calendar) var calenar
let date: Date
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 30) {
ForEach(days, id: \.self) { day in
VStack(spacing: 20) {
Text(daySymbol(date: day))
.font(.system(size: 14, weight: .regular))
if calenar.isDateInToday(day) {
Text("\(dayNumber(date: day))")
.foregroundColor(Color.white)
.background(Circle().foregroundColor(.blue)
.frame(width: 40, height: 40))
} else {
Text("\(dayNumber(date: day))")
}
}
}
}
.padding([.horizontal])
.padding(.bottom, 15)
}
}
private func dayNumber(date: Date) -> String {
let formatter = DateFormatter.dayNumber
let dayNumber = formatter.string(from: date)
return dayNumber
}
private var days: [Date] {
guard let interval = calenar.dateInterval(of: .month, for: date) else { return [] }
return calenar.generateDates(inside: interval, matching: DateComponents(hour: 0, minute: 0, second: 0))
}
private func daySymbol(date: Date) -> String {
let dayFormatter = DateFormatter.weekDay
let weekDay = dayFormatter.string(from: date)
return weekDay
}
}
1 ответ
Решение
Эта библиотека https://github.com/Amzd/ScrollViewProxy решает мою проблему.
struct WeekDaysView: View {
let date: Date
@Environment(\.calendar) var calendar
@State private var scrollTarget: Int? = nil
var body: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 30) {
ForEach(Array(zip(days.indices, days)), id: \.0) { index, day in
VStack(spacing: 20) {
Text(daySymbol(date: day))
.font(.system(size: 14, weight: .regular))
.scrollId(index)
if calendar.isDateInToday(day) {
Text("\(dayNumber(date: day))")
.foregroundColor(Color.white)
.background(Circle().foregroundColor(.blue)
.frame(width: 40, height: 40))
.onAppear {
scrollTarget = index
}
} else {
Text("\(dayNumber(date: day))")
}
}
}
}
.padding([.horizontal])
.padding(.bottom, 15)
}
.onAppear {
DispatchQueue.main.async {
withAnimation {
proxy.scrollTo(scrollTarget, alignment: .center, animated: true)
}
}
}
}
}