我不确定这是否是一个错误,或者我是否做错了什么,因为我想在我的人没有项目数组时显示警报。当我删除项目时,会显示警报,但有时警报只会显示一秒钟,然后就会消失。有时,直到我按下按钮才会显示警报,但整个文本都会变成粗体。 我已经多次启动模拟器并对其进行了测试,但我找不到任何相关性。 我的猜测是,警报被激活或显示多次,但我不知道在哪里或为什么。
这是我的代码,警报位于“SectionRowView”中。
class Person: Identifiable, ObservableObject {
let id = UUID()
@Published var name: String
@Published var item: [TodolistItem]
init(name: String, item: [TodolistItem]) {
self.name = name
self.item = item
}
}
class TodolistItem: Identifiable, ObservableObject {
@Published var todoName: String
@Published var priority: String
init(todoName: String, priority: String) {
self.todoName = todoName
self.priority = priority
}
}
struct Todolist: View {
@State private var personen: [Person] = [
Person(name: "Michi", item: [
TodolistItem(todoName: "Reifenwechsel", priority: "Niedrig"),
TodolistItem(todoName: "Irgendwas", priority: "Mittel")
]),
Person(name: "Tina", item: [
TodolistItem(todoName: "Haushalt", priority: "Dringend!")
])
]
@State private var addSheet: Bool = false
let navTitle: String
let listInfo: ListInfo
var body: some View {
NavigationStack {
List {
ForEach(personen) { person in
SectionRowView(person: person)
}
}
.listStyle(.sidebar)
}
.navigationTitle(navTitle)
.navigationBarItems(trailing:
Button(action: { addSheet.toggle() }, label: {
Image(systemName: "plus.circle")
})
)
.sheet(isPresented: $addSheet) {
AddTodoSectionView(personen: $personen)
.presentationDetents([.fraction(0.4)])
}
.toolbarBackground(listInfo.backgroundColor.opacity(0.6), for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
}
}
struct SectionRowView: View {
@State private var isExpanded: Bool = true
@State private var editSheet: Bool = false
@State private var showAlert: Bool = false
@ObservedObject var person: Person
var body: some View {
Section(isExpanded: $isExpanded) {
ForEach(person.item) { item in
HStack {
TodoRowView(item: item)
Button { editSheet.toggle() } label: {
Image(systemName: "info.circle")
}
.buttonStyle(BorderlessButtonStyle())
.foregroundStyle(.primary)
}
}
.onDelete { offSet in
person.item.remove(atOffsets: offSet)
if person.item.isEmpty {
showAlert = true
}
}
.sheet(isPresented: $editSheet) {
EditView()
}
Button {
let newItem = TodolistItem(todoName: "Opfer", priority: "Niedrig")
withAnimation {
person.item.append(newItem)
}
} label: {
HStack {
Image(systemName: "plus")
Text("Neues Todo hinzufügen")
}
.foregroundStyle(.blue)
}
} header: {
Text(person.name)
}
.alert("Person löschen?", isPresented: $showAlert) {
Button("Behalten", role: .cancel) {
showAlert = false
}
Button("Löschen", role: .destructive) {
showAlert = false
}
} message: {
Text("Die Person hat alle Aufgaben erledigt, möchtest du das diese gelöscht wird?")
}
}
}
struct TodoRowView: View {
@State private var priority: [String] = [
"Niedrig", "Mittel", "Hoch", "Dringend!"
]
@State private var isDone: Bool = false
@State private var textFieldText: String = ""
@ObservedObject var item: TodolistItem
var body: some View {
VStack {
HStack {
Button(action: {
guard textFieldText != "" else { return }
withAnimation {
isDone.toggle()
}
}, label: {
Image(systemName: isDone ? "checkmark.circle.fill" : "checkmark.circle")
.foregroundStyle(isDone ? .green : .red)
})
TextField(item.todoName, text: $textFieldText, prompt: Text("Todo eintragen"))
.strikethrough(isDone ? true : false)
.foregroundStyle(isDone ? Color.gray.opacity(0.7) : Color.primary)
Spacer()
if item.priority == "Niedrig" {
Menu(item.priority) {
ForEach(priority, id: \.self) { prio in
Button(prio) {
item.priority = prio
}
}
}
.foregroundStyle(.green)
} else if item.priority == "Mittel" {
Menu(item.priority) {
ForEach(priority, id: \.self) { prio in
Button(prio) {
item.priority = prio
}
}
}
.foregroundStyle(.blue)
} else if item.priority == "Hoch" {
Menu(item.priority) {
ForEach(priority, id: \.self) { prio in
Button(prio) {
item.priority = prio
}
}
}
.foregroundStyle(.orange)
} else if item.priority == "Dringend!" {
Menu(item.priority) {
ForEach(priority, id: \.self) { prio in
Button(prio) {
item.priority = prio
}
}
}
.foregroundStyle(.red)
}
}
}
}
}
struct EditView: View {
var body: some View {
Text("Hi")
}
}
struct AddTodoSectionView: View {
@State private var sectionTextField: String = ""
@Binding var personen: [Person]
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationStack {
VStack {
TextField("", text: $sectionTextField, prompt: Text("Füge eine neue Person hinzu"))
.frame(width: 250, height: 50)
.padding(.horizontal)
.background(Color.gray.opacity(0.3).cornerRadius(10))
.padding(.horizontal)
Button("Save") { addItem() }
.frame(width: 250, height: 50)
.padding(.horizontal)
.background(Color.gray.opacity(0.3).cornerRadius(10))
.padding(.horizontal)
}
.navigationTitle("Neue Person")
}
}
func addItem() {
let newItem = Person(name: sectionTextField, item: [TodolistItem(todoName: "Test1", priority: "Niedrig")])
personen.append(newItem)
dismiss()
}
}
#Preview {
Todolist(navTitle: "Todoliste", listInfo: ListInfo(listName: "", backgroundColor: .blue, accentColor: .white))
}
当某个项目从某人的项目列表中删除时,这会导致
SectionRowView
的刷新。这是因为,这个视图正在观察person
的变化。如果同时设置了标志showAlert
(当删除最后一个项目时会发生这种情况),那么我猜想刷新视图和显示警报之间存在竞争条件。有时,刷新期间标志的更改会丢失。
我发现一种修复方法是通过在一小段延迟后异步执行来推迟设置标志(0.5 秒似乎就足够了)。但我认为这不是一个好的解决方案。
从更大的角度来看,如果在
SectionRowView
内部执行删除该人的按钮操作,您打算如何实现?该视图没有人员数组的句柄。所以:
👉 我建议将警报移至父视图
Todolist
。
personen
。这些改变让它以这种方式工作:
// Todolist
@State private var personIdWithoutItems: UUID?
@State private var showAlert: Bool = false
// ...
List {
// ...
}
.listStyle(.sidebar)
.onChange(of: personIdWithoutItems) { oldVal, newVal in
if newVal != nil {
showAlert = true
}
}
.alert("Person löschen?", isPresented: $showAlert) {
Button("Behalten", role: .cancel) {
personIdWithoutItems = nil
showAlert = false
}
Button("Löschen", role: .destructive) {
personIdWithoutItems = nil
showAlert = false
}
} message: {
Text("Die Person hat alle Aufgaben erledigt, möchtest du das diese gelöscht wird?")
}
// SectionRowView
// @State private var showAlert: Bool = false // -> delete
@Binding var personIdWithoutItems: UUID?
// ...
ForEach(person.item) { item in
// ...
}
.onDelete { offSet in
person.item.remove(atOffsets: offSet)
if person.item.isEmpty {
personIdWithoutItems = person.id
}
}
// .alert("Person löschen?", isPresented: $showAlert) { // -> delete