弹出框在 ForEach 中显示不准确的信息

问题描述

我遇到了一个问题,我在 NavigationView 中有一个 ForEach 循环。当我单击“编辑”按钮,然后单击每一行右侧的铅笔图像时,我希望它显示我们在 ForEach 循环中使用的文本变量。但是,当我单击 test123 以外的文本的铅笔图像时,它仍然显示文本 test123,我完全不知道为什么。

Here's 一个视频。为什么会发生这种情况?

import SwiftUI

struct TestPopOver: View {
    
    private var stringObjects = ["test123","helloworld","reddit"]
    
    @State private var editMode: EditMode = .inactive
    @State private var showThemeEditor = false
        
    @viewbuilder
    var body: some View {
        NavigationView {
            List {
                ForEach(self.stringObjects,id: \.self) { text in
                    NavigationLink( destination: HStack{Text("Test!")}) {
                        HStack {
                            Text(text)
                            Spacer()
                            if self.editMode.isEditing {
                                Image(systemName: "pencil.circle").imageScale(.large)
                                    .onTapGesture {
                                        if self.editMode.isEditing {
                                            self.showThemeEditor = true
                                        }
                                    }
                            }
                            
                        }
                    }
                    .popover(isPresented: $showThemeEditor) {
                        CustomPopOver(isShowing: $showThemeEditor,text: text)
                    }
                    
                }
            }
            .navigationBarTitle("Reproduce Editing Bug!")
            .navigationBarItems(leading: EditButton())
            .environment(\.editMode,$editMode)

        }
    }
}

struct CustomPopOver: View {
    @Binding var isShowing: Bool
    var text: String
    var body: some View {
        vstack(spacing: 0) {
            HStack() {
                Spacer()
                Button("Cancel") {
                    self.isShowing = false
                }.padding()
            }
            Divider()
            List {
                Section {
                    Text(text)
                }
            }.listStyle(GroupedListStyle())
        }
        
    }
}

解决方法

这是一个非常常见的问题(尤其是从 iOS 14 开始),它会在 sheet 中遇到很多,但也会影响 popover

您可以通过使用 popover(item:) 而不是 isPresented 来避免它。在这种情况下,它实际上会使用最新的值,而不仅仅是在查看第一次渲染或第一次设置时出现的值。

struct EditItem : Identifiable { //this will tell it what sheet to present
    var id = UUID()
    var str : String
}

struct ContentView: View {
    
    private var stringObjects = ["test123","helloworld","reddit"]
    
    @State private var editMode: EditMode = .inactive
    @State private var editItem : EditItem? //the currently presented sheet -- nil if no sheet is presented
    
    @ViewBuilder
    var body: some View {
        NavigationView {
            List {
                ForEach(self.stringObjects,id: \.self) { text in
                    NavigationLink( destination: HStack{Text("Test!")}) {
                        HStack {
                            Text(text)
                            Spacer()
                            if self.editMode.isEditing {
                                Image(systemName: "pencil.circle").imageScale(.large)
                                    .onTapGesture {
                                        if self.editMode.isEditing {
                                            self.editItem = EditItem(str: text) //set the current item
                                        }
                                    }
                            }
                            
                        }
                    }
                    .popover(item: $editItem) { item in //item is now a reference to the current item being presented
                        CustomPopOver(text: item.str)
                    }
                    
                }
            }
            .navigationBarTitle("Reproduce Editing Bug!")
            .navigationBarItems(leading: EditButton())
            .environment(\.editMode,$editMode)

        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

struct CustomPopOver: View {
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>

    var text: String
    var body: some View {
        VStack(spacing: 0) {
            HStack() {
                Spacer()
                Button("Cancel") {
                    self.presentationMode.wrappedValue.dismiss()
                }.padding()
            }
            Divider()
            List {
                Section {
                    Text(text)
                }
            }.listStyle(GroupedListStyle())
        }
        
    }
}

我还选择使用 presentationMode 环境属性关闭弹出框,但您可以传递 editItem 绑定并将其设置为 nil@Binding var editItem : EditItem?editItem = nil)。前者更惯用一点。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...