Я хочу иметь возможность выбрать несколько элементов (например, первые 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, но не могу заставить его работать, буду признателен за любую помощь.





вам нужно новое свойство в вашей структуре Day, чтобы отслеживать выбор. Я назвал это selected.
вы должны объявить year как @State var — так что это источник истины для вашего представления, и его можно изменить.
Чтобы сделать day изменяемым в представлении, вы должны передать год, месяц и день вниз, используя инициализатор $ ForEach.
(2. и 3. можно решить более элегантно, используя класс ObservableObject для ваших базовых данных)
Измените цвет капсулы на основе day.selected.
Переключатель жестов при касании 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)
}
}
}
}
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()
}
}
Ответы только на код не так полезны, как могли бы быть. Лучше также включить объяснение того, что было не так в вопросе и как ответ решает проблему.
Большое спасибо за вашу помощь, однако есть ли способ изменить это, чтобы вместо нажатия пользователем я мог иметь переменную (например, 20) и чтобы первые 20 капсул в сетке были другого цвета? Я думаю, что неправильно сформулировал проблему, но это все равно определенно помогает, спасибо!