表格修改器的SwiftUI问题

时间:2019-08-23 18:56:21

标签: swiftui

我的应用程序中有一个初始视图,需要打开一些模式视图。我正在使用的数据来自核心数据,并且我使用@FetchedRequest属性包装器填充了列表视图。我要制作的UI与您在iOS 13的“提醒”应用中创建和编辑列表的方式类似。

  • 添加记录-允许用户随时创建新的列表(以后将创建子对象)。
  • 编辑记录-将“列表”视图切换到“编辑”模式,点击一行上的“编辑”按钮以打开模式以编辑记录。

这两个都是现在工作的 ,但是存在一些问题。

  1. 当我关闭“添加”模式时,有时 我无法点击视图右上方的“编辑”按钮。点按时什么也不会发生。我尝试附加打印状态语句,但没有被调用。这种情况通常发生在大多数时间,但并非总是如此。

  2. 当我使用上述过程编辑记录时,请点按“取消”或“完成”以关闭该模式。但是之后,我将无法使用此功能。如果我尝试打开另一个编辑模型,它将打开,但是传递给它的数据永远不会显示在该字段中。

我将它们分为两个视图和表格,因为当我将它们合并为一个视图和表格时遇到了很多问题。

更新:根据this的回答,通过将两个.sheet修改器都移到NavigationView之外并将它们附加到某些隐藏对象上,解决了问题1。

关于问题2,我今天晚上花了一些时间尝试一些不同的事情,我认为我可以明白问题出在哪里。初次使用后,重新打开编辑模态时,它将经历任何类型的初始化过程。没有调用初始化,甚至没有调用附加到视图的onAppear()。在这种情况下,永远不会用记录中的值填充文本字段使用的@State变量,因为不会再次调用文本字段代码。我不知道该如何处理。在任何其他环境中,我只删除该实例并创建一个新实例,但是我不知道如何删除该模式创建的Edit视图的缓存实例。

更新:自2019年8月27日起,第二个问题已在iOS 13.1中修复。我什至不必重新编译即可查看修复程序。

列表视图

已更新,可将图纸移动到NavigationView之外

import SwiftUI

struct TimelineListView: View {

    @Environment(\.managedObjectContext) var managedObjectContext

    @FetchRequest(fetchRequest: Timeline.allTimelinesFetchRequest()) var timelines: FetchedResults<Timeline>

    @State var listViewEditMode: EditMode = .inactive

    @State var openModalSheetAdd = false

    @State var openModalSheetEdit = false
    @State var timelineToEdit: Timeline?

    var body: some View {
        VStack{
                NavigationView {
                    VStack {

                        List(self.timelines) { timeline in

                            NavigationLink(destination: TimelineDetailView(timeline: timeline)) {

                                HStack{
                                    Text(timeline.name ?? "Unnamed List")
                                    if (self.listViewEditMode == .active) {
                                        Spacer()
                                        Image(systemName: "info.circle")
                                            .onTapGesture {
                                                self.timelineToEdit = timeline
                                                self.listViewEditMode = .inactive
                                                self.openModalSheetEdit = true
                                        }
                                    }
                                }

                            } //  End Navigation Link

                        } // End List

                        HStack {
                            Spacer()
                            Button("Add List") {
                                self.openModalSheetAdd = true
                            }.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 20))
                        }
                    }

                    .navigationBarTitle(Text("Lists"), displayMode: .inline)
                    .navigationBarItems(trailing: EditButton())

                        .environment(\.editMode, self.$listViewEditMode)

                }// End Navigation View

            // Edit modal
            Text("").hidden()
                .sheet(isPresented: $openModalSheetEdit,
                       onDismiss: {
                        self.openModalSheetEdit = false
                },
                       content: {
                        TimelineEditView(timeline: self.timelineToEdit, onDismiss: {
                            self.openModalSheetEdit = false // this is here because sometimes onDismiss is not called.
                        })
                            .environment(\.managedObjectContext, self.managedObjectContext)
                })

            // Add modal
            Text("").hidden()
                .sheet(isPresented: $openModalSheetAdd,
                       onDismiss: {
                        self.openModalSheetAdd = false
                },
                       content: {
                        TimelineAddView(onDismiss: {
                            self.openModalSheetAdd = false // this is here because sometimes onDismiss is not called.
                        })
                            .environment(\.managedObjectContext, self.managedObjectContext)
                })
        }

    }
}

添加记录视图

struct TimelineAddView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    @State private var nameEdit: String = ""


    // This closure is here to call when we dismiss the modal because onDismiss is not always called
    var onDismiss: () -> ()

    var body: some View {

        VStack {
            HStack {

                Button(action: ({
                    self.nameEdit = ""
                    self.presentationMode.wrappedValue.dismiss()
                    self.onDismiss()
                })) {
                    Text("Cancel")
                }
                .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 0))

                Spacer()

                Button(action: ({
                    let newTimeline = Timeline(context: self.managedObjectContext)
                    newTimeline.name = self.nameEdit
                    self.nameEdit = ""
                    do {
                        try self.managedObjectContext.save()
                    } catch {
                        print(error)
                    }
                    self.presentationMode.wrappedValue.dismiss()
                    self.onDismiss()
                })) {
                    Text("Done")
                }
                .padding(EdgeInsets(top: 10, leading: 0, bottom: 0, trailing: 10))
            }

            TextField("Data to edit", text: self.$nameEdit)
                .shadow(color: .secondary, radius: 1, x: 0, y: 0)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .onAppear {
                    self.nameEdit = ""
            }.padding()
            Spacer()
        }
    }
}

编辑记录视图

struct TimelineEditView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    @State private var nameEdit = ""
    var timeline : Timeline?

    // This closure is here to call when we dismiss the modal because onDismiss is not always called
    var onDismiss: () -> ()

    var body: some View {

        return VStack {
            HStack {
                Button(action: ({
                    // Dismiss the modal sheet
                    self.nameEdit = ""
                    self.presentationMode.wrappedValue.dismiss()
                    self.onDismiss()
                })) {
                    Text("Cancel")
                }
                .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 0))

                Spacer()
                Button(action: ({

                    self.timeline?.name = self.nameEdit

                    do {
                        try self.managedObjectContext.save()
                    } catch {
                        print(error)
                    }

                    // Dismiss the modal sheet
                    self.nameEdit = ""
                    self.presentationMode.wrappedValue.dismiss()
                    self.onDismiss()
                })) {
                    Text("Done")
                }
                .padding(EdgeInsets(top: 10, leading: 0, bottom: 0, trailing: 10))
            }

            TextField("Data to edit", text: self.$nameEdit)
                .shadow(color: .secondary, radius: 1, x: 0, y: 0)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .onAppear {
                    self.nameEdit = self.timeline?.name ?? ""
            }.padding()
            Spacer()
        }
    }
}

2 个答案:

答案 0 :(得分:3)

嵌入到.sheet中的

List只会打开一次,这是一个已知的错误,我希望他们可以修复它。在此之前,您必须将.sheet移到任何List之外。

但是由于.sheet不在List内,而是在NavigationView内,因此尝试将.sheet移出它可能是一个好主意。

但是不要将两个.sheet附加到两个相同的视图中,而应通过以下方式添加它们:

VStack{
    NavigationView{ ... }
    Text("").hidden().sheet(...)
    Text("").hidden().sheet(...)
}

答案 1 :(得分:0)

我对ScrollView有相同的问题。 需要从sheet中添加ScrollView,以确保我们可以多次打开。

ScrollView {
    [...]
}.sheet([...])

如果您将视图提取到另一个视图(例如,以DatePicker为例),这实际上是不实际的。