0

Hi everyone I'm working with a LazyHGrid The grid shows 19 cells divided on 2 lines and their contents are times that the user can select.

I have a problem with the preselection, i.e. I would like that when the horizontal grid is shown, a preselection based on the current time is visible for example

I'll give you an example of the grid


| 9:30 | - | 10:00 | - | 10:30 | - | 11:00 |


If at this time it is 10:20 am I would like the cell containing the text 10:30 to be automatically selected when the user sees the grid for the first time


| 9:30 | - | 10:00 | - | 10:30 | - | 11:00 |
Preselection at 10:30 if current time is 10:20


In a nutshell I would need the selection of the cell that contains a time half an hour ahead of the current time

This is what I have done so far

Can you help me?

struct TimeSelectorView: View {
    
    @State private var selectedItem: Int = 0
    
    @Binding var date: Date
    
    var body: some View {
        
        VStack (alignment: .center, spacing: 20) {
            ScrollView(.horizontal, showsIndicators: false) {
                ScrollViewReader { reader in
                    LazyHGrid(rows: Array(repeating: GridItem(.adaptive(minimum: 100, maximum: .infinity), spacing: 0), count: 2), spacing: 0) {
                        ForEach(reservationTimeItems.indices) { value in
                        
                            TimeSelectorCellView(selectedItem: $selectedItem, 
                              date: $date, 
                              hours: reservationTimeItems[value].hour, 
                              minute: reservationTimeItems[value].minute, 
                              item: value)
                                
                            .frame(width: (screen.size.width - 20 ) / 4)
                            .padding([.top, .bottom], 10)
                            .id(value)
                        }
                    }
                    .onAppear { scrollTo((8, 12, 0), reader) }
                    .onChange(of: date) { _ in scrollTo((8, 12, 0), reader) }
                    .onChange(of: selectedItem) { newValue in

                    date = Calendar.current.date(bySettingHour: reservationTimeItems[newValue].hour, 
                    minute: reservationTimeItems[newValue].minute, 
                    second: 0, of: date)!
                }
                }
            }
            .frame(height: 110)
        }
    }
}

struct TimeSelectorCellView: View {
       
    @Binding var selectedItem: Int
    @Binding var date: Date
    
    private var selectionColor: Color { selected ? .greenApp : .white }
    private var selectionOpacity: CGFloat { selected ? 1 : 0 }
    
    private var selected: Bool {
        selectedItem == item
    }
    
    private var disableItem: Bool {
        // Disabilita la cella nel caso in cui la data selezionata è quella di oggi e l'orario della data corrente è inferiore a quello contenuto nella cella
        Date().checkTime(hour: hours, minute: minute) && date.isToday()
        // oppure se la data selezionata è inferiore a quella corrente
        || date.isPreviousDate()
    }
    
    var hours: Int // Ore della data
    var minute: Int // Minuti della data
    var item: Int

    var body: some View {
        
        VStack(alignment: .leading, spacing: 10) {
            
            HStack(alignment: .center, spacing: 2) {
                                
                Text(hours < 10 ? "0\(hours)" : "\(hours)")
                    .foregroundColor(disableItem ? disabledColor : selectionColor)
                    .font(.system(size: 23))
                
                // Minuti
                HStack(spacing: 3) {
                    Text(":").foregroundColor(.white)
                    Text(minute < 10 ? "0\(minute)" : "\(minute)")
                        .foregroundColor(disableItem ? disabledColor : selectionColor)
                }
                .font(.footnote)
            }
        }
        // Selezione e feedback tattile
        .onTapGesture {
            UIImpactFeedbackGenerator(style: .medium).impactOccurred()

            DispatchQueue.main.async {
                withAnimation(.easeInOut(duration: animationDuration)) {
                    // Gestisce la selezione della cella
                        selectedItem = item
                }
            }
        }
        .disabled(disableItem)
    }
}
4

1 回答 1

1

The type of reservationTimeItems is not specified in the provided code, so assuming that reservationTimeItems is of type [ReservationTime], where ReservationTime is defined as follow:

struct ReservationTime: Identifiable, Equatable {
    let id: UUID = UUID()
    var hour: Int
    var minute: Int
    
    static func ==(lhs: ReservationTime, rhs: ReservationTime) -> Bool {
        lhs.hour == rhs.hour && lhs.minute == rhs.minute
    }
}

I would add this extension:

extension Date {
    var hour: Int {
        Calendar.current.dateComponents([.hour], from: self).hour ?? 0
    }
    var minute: Int {
        Calendar.current.dateComponents([.minute], from: self).minute ?? 0
    }
    var nextReservationTime: ReservationTime {
        let nextHalfHour = self.minute < 30 ? self.hour : (self.hour + 1) % 24
        let nextHalfMinute = self.minute < 30 ? 30 : 0
        
        return ReservationTime(hour: nextHalfHour, minute: nextHalfMinute)
    }
}

and then, in TimeSelectorView:

struct TimeSelectorView: View {
    @State private var selectedItem: Int = 0  

    // ...
    
    var body: some View {
        VStack(alignment: .center, spacing: 20) {
            // ...
        }.onAppear {
            selectedItem = reservationTimeItems.firstIndex(of: Date().nextReservationTime) ?? 0
        }
    }
}
于 2022-01-30T17:12:00.223 回答