Как я могу изменить определенное количество элементов в LazyGrid SwiftUI?

Я хочу иметь возможность выбрать несколько элементов (например, первые 20) в сетке и изменить цвет элементов.

import SwiftUI

struct ContentView: View {
    @State var showView = false
    @State private var birthDate = Date.now
    struct Day: Identifiable {
        let id = UUID()
        let value: Int
    }
    
    struct Month {
        let name: String
        let numberOfDays: Int
        var days: [Day]

        init(name: String, numberOfDays: Int) {
            self.name = name
            self.numberOfDays = numberOfDays
            self.days = []

            for n in 1...numberOfDays {
                self.days.append(Day(value: n))
            }

        }
    }
    
    let year = [
        Month(name: "Youth", numberOfDays: 12),
        Month(name: "Teenager", numberOfDays: 7),
        Month(name: "20s - 30s", numberOfDays: 20),
        Month(name: "Middle ages", numberOfDays: 26),
        Month(name: "Retirement", numberOfDays: 35),
    ]
    let layout = [
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
        ]
    
    var body: some View {
        VStack {
                   DatePicker(selection: $birthDate, in: ...Date.now, displayedComponents: .date) {
                   }

                   Text("Your Birthdate is \(birthDate.formatted(date: .long, time: .omitted))")
               
            ScrollView {
                
                LazyVGrid(columns: layout, pinnedViews: [.sectionHeaders]) {
                    ForEach(year, id: \.name){ month in
                        Section(header: Text(verbatim: month.name).font(.headline)) {
                            ForEach(month.days) { day in
                                Capsule()
                            }
                       }
                    }
                }.padding(5)
            }  
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Вот как это выглядит.

скриншот приложения на данный момент

и это то, что я хочу сделать - плохо интегрирую дату, но нужен способ изменить определенное их количество (в этом примере 7 из них были изменены:

тот же скриншот с 7 выбранными элементами и измененным цветом с синего на черный

Я пробовал ForEach, но не могу заставить его работать, буду признателен за любую помощь.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
374
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

  1. вам нужно новое свойство в вашей структуре Day, чтобы отслеживать выбор. Я назвал это selected.

  2. вы должны объявить year как @State var — так что это источник истины для вашего представления, и его можно изменить.

  3. Чтобы сделать day изменяемым в представлении, вы должны передать год, месяц и день вниз, используя инициализатор $ ForEach.

(2. и 3. можно решить более элегантно, используя класс ObservableObject для ваших базовых данных)

  1. Измените цвет капсулы на основе day.selected.

  2. Переключатель жестов при касании day.selected.

struct ContentView: View {
    
    @State var showView = false
    @State private var birthDate = Date.now
    
    
    struct Day: Identifiable {
        let id = UUID()
        let value: Int
        var selected: Bool = false // new property here
    }
    
    struct Month {
        let name: String
        let numberOfDays: Int
        var days: [Day]

        init(name: String, numberOfDays: Int) {
            self.name = name
            self.numberOfDays = numberOfDays
            self.days = []

            for n in 1...numberOfDays {
                self.days.append(Day(value: n))
            }

        }
    }
    
    @State var year = [   // define year as State to make it changeable
        Month(name: "Youth", numberOfDays: 12),
        Month(name: "Teenager", numberOfDays: 7),
        Month(name: "20s - 30s", numberOfDays: 20),
        Month(name: "Middle ages", numberOfDays: 26),
        Month(name: "Retirement", numberOfDays: 35),
    ]
    
    let layout = [
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
            GridItem(.flexible(minimum: 40)),
        ]
    
    var body: some View {
        VStack {
            DatePicker(selection: $birthDate, in: ...Date.now, displayedComponents: .date) {
            }
            
            Text("Your Birthdate is \(birthDate.formatted(date: .long, time: .omitted))")
            
            ScrollView {
                
                LazyVGrid(columns: layout, pinnedViews: [.sectionHeaders]) {
                    ForEach($year, id: \.name){ $month in  // binding init
                        Section(header: Text(verbatim: month.name).font(.headline)) {
                            ForEach($month.days) { $day in // binding init
                                Capsule()
                                    .frame(height: 20)
                                    .foregroundColor(day.selected ? .red : .cyan) // different colors based on selected
                                    .onTapGesture {
                                        day.selected.toggle() // on Tap toggle selected
                                    }
                            }
                        }
                    }
                }.padding(5)
            }
        }
    }
}

Большое спасибо за вашу помощь, однако есть ли способ изменить это, чтобы вместо нажатия пользователем я мог иметь переменную (например, 20) и чтобы первые 20 капсул в сетке были другого цвета? Я думаю, что неправильно сформулировал проблему, но это все равно определенно помогает, спасибо!

TotalSoda 19.12.2022 01:49
Ответ принят как подходящий

Надеюсь, это поможет):

import SwiftUI

struct ContentView: View {
    @State var showView = false
    @State private var birthDate = Date.now
    struct Day: Identifiable {
        let id = UUID()
        let value: Int
    }

    struct Month {
        let name: String
        let numberOfDays: Int
        var days: [Day]

        init(name: String, numberOfDays: Int) {
            self.name = name
            self.numberOfDays = numberOfDays
            days = []

            for n in 1 ... numberOfDays {
                days.append(Day(value: n))
            }
        }
    }

    let year = [
        Month(name: "Youth", numberOfDays: 12),
        Month(name: "Teenager", numberOfDays: 7),
        Month(name: "20s - 30s", numberOfDays: 20),
        Month(name: "Middle ages", numberOfDays: 26),
        Month(name: "Retirement", numberOfDays: 35),
    ]
    let layout = [
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
        GridItem(.flexible(minimum: 40)),
    ]
    @State private var selected: Set<Day.ID> = []
    init() {
        guard let selectedDays = year.first?.days else { return }
        _selected = .init(initialValue: .init(selectedDays.map { $0.id }))
    }

    var body: some View {
        VStack {
            DatePicker(selection: $birthDate, in: ...Date.now, displayedComponents: .date) {}

            Text("Your Birthdate is \(birthDate.formatted(date: .long, time: .omitted))")

            ScrollView {
                LazyVGrid(columns: layout, pinnedViews: [.sectionHeaders]) {
                    ForEach(year, id: \.name) { month in
                        Section(header: Text(verbatim: month.name).font(.headline)) {
                            ForEach(month.days) { day in
                                Capsule()
                                    .fill(isSelected(id: day.id) ? .gray : .cyan)
                            }
                        }
                    }
                }.padding(5)
            }
        }
    }

    private func isSelected(id: Day.ID) -> Bool {
        return selected.contains(id)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Ответы только на код не так полезны, как могли бы быть. Лучше также включить объяснение того, что было не так в вопросе и как ответ решает проблему.

HangarRash 20.12.2022 19:58

Другие вопросы по теме