admin管理员组

文章数量:1400572

Hi Stack Overflow community, I have a problem. I want to create a date picker based on a ScrollView where the starting date is today, and the range is 15 days forward and backward. For some reason, SwiftUI doesn't navigate to values that are off-screen, and also, during initialization, it doesn't scroll to today's date, which is currently March 25th. Is this a known issue? I tried various methods like using DispatchQueue delays or Task.sleep, but nothing works. I would appreciate any help.

PS: When I changed the values to Int, everything works, so something is wrong with handling dates.

Code example:

import SwiftUI

struct ContentView: View {
    private let dates: [Date] = {
        let today = Date()
        let calendar = Calendar.current
        return (0...30)
            .map {
                calendar.date(byAdding: .day,
                              value: $0 - 15,
                              to: today)!
            }
    }()
    
    @State var selectedDate: Date = Date()
    
    var body: some View {
        GeometryReader { geometry in
            ScrollViewReader { scrollValue in
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(dates, id: \.self) { date in
                            DateCell(date: date, isSelected: Calendar.current.isDate(date, inSameDayAs: selectedDate))
                                .id(date)
                                .onTapGesture {
                                    withAnimation {
                                        selectedDate = date
                                    }
                                }
                        }
                    }
                    .padding(.horizontal, geometry.size.width / 2)
                }
                .onChange(of: selectedDate, initial: true) { _, newValue in
                    withAnimation {
                        scrollValue.scrollTo(newValue, anchor: .center)
                    }
                }
            }
        }
    }
}

struct DateCell: View {
    let date: Date
    var isSelected: Bool
    
    var body: some View {
        VStack {
            Text(date, format: .dateTime.weekday(.short))
            Text(date, format: .dateTime.day())
                .bold()
        }
        .frame(width: 50, height: 50)
        .background(isSelected ? Color.red : Color.gray.opacity(0.3))
        .clipShape(Circle())
    }
}

#Preview {
    ContentView()
}

Hi Stack Overflow community, I have a problem. I want to create a date picker based on a ScrollView where the starting date is today, and the range is 15 days forward and backward. For some reason, SwiftUI doesn't navigate to values that are off-screen, and also, during initialization, it doesn't scroll to today's date, which is currently March 25th. Is this a known issue? I tried various methods like using DispatchQueue delays or Task.sleep, but nothing works. I would appreciate any help.

PS: When I changed the values to Int, everything works, so something is wrong with handling dates.

Code example:

import SwiftUI

struct ContentView: View {
    private let dates: [Date] = {
        let today = Date()
        let calendar = Calendar.current
        return (0...30)
            .map {
                calendar.date(byAdding: .day,
                              value: $0 - 15,
                              to: today)!
            }
    }()
    
    @State var selectedDate: Date = Date()
    
    var body: some View {
        GeometryReader { geometry in
            ScrollViewReader { scrollValue in
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(dates, id: \.self) { date in
                            DateCell(date: date, isSelected: Calendar.current.isDate(date, inSameDayAs: selectedDate))
                                .id(date)
                                .onTapGesture {
                                    withAnimation {
                                        selectedDate = date
                                    }
                                }
                        }
                    }
                    .padding(.horizontal, geometry.size.width / 2)
                }
                .onChange(of: selectedDate, initial: true) { _, newValue in
                    withAnimation {
                        scrollValue.scrollTo(newValue, anchor: .center)
                    }
                }
            }
        }
    }
}

struct DateCell: View {
    let date: Date
    var isSelected: Bool
    
    var body: some View {
        VStack {
            Text(date, format: .dateTime.weekday(.short))
            Text(date, format: .dateTime.day())
                .bold()
        }
        .frame(width: 50, height: 50)
        .background(isSelected ? Color.red : Color.gray.opacity(0.3))
        .clipShape(Circle())
    }
}

#Preview {
    ContentView()
}

Share Improve this question edited Mar 25 at 12:30 miltenkot asked Mar 25 at 12:21 miltenkotmiltenkot 3131 silver badge10 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 1

This problem is probably happening because Date() gives you a date that is accurate to some fraction of a second (nanoseconds?). So the date you use to initialize the collection is going to be different to the date that you use to initialize selectedDate. In other words, the initial value of selectedDate will not be present in the array of dates.

To fix, try truncating the dates to start of day. Calendar has a function that does this:

private let dates: [Date] = {
    let calendar = Calendar.current
    let today = calendar.startOfDay(for: Date()) // 

本文标签: swiftuiScrollTo with ScrollViewReader doesn39t work onAppear using Date as dataStack Overflow