sheet 修饰符的 SwiftUI 问题
SwiftUI Issues with sheet modifier
我的应用程序中有一个初始视图需要打开一些模态视图。我正在使用的数据来自核心数据,我正在使用 @FetchedRequest
属性 包装器填充列表视图。 UI 我尝试创建的方式与您在 iOS 13.
的提醒应用程序中创建和编辑列表的方式类似
- 添加记录 - 允许用户随时创建新列表(子对象在后面)。
- 编辑记录 - 将列表视图切换到编辑模式,点击一行上的编辑按钮打开模式以编辑记录。
这两个现在都有点在工作,但是有一些问题。
当我关闭“添加”模式时,有时我无法点击视图右上角的“编辑”按钮。点击时什么也不会发生。我尝试附加打印状态语句但没有被调用。大多数时候都会发生这种情况,但并非总是如此。
当我使用上述过程编辑记录时,当点击取消或完成关闭此模式时,它会关闭。但在这一点之后我不能使用这个功能。如果我尝试打开另一个编辑模型,它会打开,但我传递给它的数据永远不会显示在该字段中。
我将它们分成两个视图和 sheet 是因为当我将它们组合成一个视图和 sheet.
时遇到了很多问题
更新:问题 1 已通过将两个 .sheet 修饰符移出 NavigationView 并将它们附加到一些隐藏对象来解决,根据 回答。
关于问题 2,今晚我花了一些时间尝试了一些不同的事情,我想我可以看出问题所在。当编辑模式在初次使用后 重新打开 时,它会经历任何类型的初始化过程。没有调用初始化,甚至没有调用附加到视图的 onAppear()
。在这种情况下,文本字段使用的@State 变量永远不会填充记录中的值,因为不会再次调用文本字段代码。我不知道如何处理这个。在任何其他环境中,我只会删除该实例并创建一个新实例,但我不知道如何删除模态创建的编辑视图的缓存实例。
更新: 自 2019.08.27 起,第二个问题已在 iOS 13.1 中修复。我什至不必重新编译就可以看到修复。
列表视图
已更新以将 sheet 移出 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()
}
}
}
.sheet
被嵌入到 List
中只打开一次是一个已知错误,我希望他们修复它。在那之前,您必须将 .sheet
移到任何 List
.
之外
但由于 .sheet
不在 List
内,而是在 NavigationView
内,因此尝试将 .sheet
移出它可能是个好主意。
但不要附加两个 .sheet
两个相同的视图,而是按以下方式添加它们:
VStack{
NavigationView{ ... }
Text("").hidden().sheet(...)
Text("").hidden().sheet(...)
}
我和 ScrollView
有同样的问题。
sheet
需要从 ScrollView
中添加,以确保我们可以多次打开。
ScrollView {
[...]
}.sheet([...])
如果将视图提取到另一个视图(例如 DatePicker)中,这确实不切实际。
我的应用程序中有一个初始视图需要打开一些模态视图。我正在使用的数据来自核心数据,我正在使用 @FetchedRequest
属性 包装器填充列表视图。 UI 我尝试创建的方式与您在 iOS 13.
- 添加记录 - 允许用户随时创建新列表(子对象在后面)。
- 编辑记录 - 将列表视图切换到编辑模式,点击一行上的编辑按钮打开模式以编辑记录。
这两个现在都有点在工作,但是有一些问题。
当我关闭“添加”模式时,有时我无法点击视图右上角的“编辑”按钮。点击时什么也不会发生。我尝试附加打印状态语句但没有被调用。大多数时候都会发生这种情况,但并非总是如此。
当我使用上述过程编辑记录时,当点击取消或完成关闭此模式时,它会关闭。但在这一点之后我不能使用这个功能。如果我尝试打开另一个编辑模型,它会打开,但我传递给它的数据永远不会显示在该字段中。
我将它们分成两个视图和 sheet 是因为当我将它们组合成一个视图和 sheet.
时遇到了很多问题更新:问题 1 已通过将两个 .sheet 修饰符移出 NavigationView 并将它们附加到一些隐藏对象来解决,根据
关于问题 2,今晚我花了一些时间尝试了一些不同的事情,我想我可以看出问题所在。当编辑模式在初次使用后 重新打开 时,它会经历任何类型的初始化过程。没有调用初始化,甚至没有调用附加到视图的 onAppear()
。在这种情况下,文本字段使用的@State 变量永远不会填充记录中的值,因为不会再次调用文本字段代码。我不知道如何处理这个。在任何其他环境中,我只会删除该实例并创建一个新实例,但我不知道如何删除模态创建的编辑视图的缓存实例。
更新: 自 2019.08.27 起,第二个问题已在 iOS 13.1 中修复。我什至不必重新编译就可以看到修复。
列表视图
已更新以将 sheet 移出 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()
}
}
}
.sheet
被嵌入到 List
中只打开一次是一个已知错误,我希望他们修复它。在那之前,您必须将 .sheet
移到任何 List
.
但由于 .sheet
不在 List
内,而是在 NavigationView
内,因此尝试将 .sheet
移出它可能是个好主意。
但不要附加两个 .sheet
两个相同的视图,而是按以下方式添加它们:
VStack{
NavigationView{ ... }
Text("").hidden().sheet(...)
Text("").hidden().sheet(...)
}
我和 ScrollView
有同样的问题。
sheet
需要从 ScrollView
中添加,以确保我们可以多次打开。
ScrollView {
[...]
}.sheet([...])
如果将视图提取到另一个视图(例如 DatePicker)中,这确实不切实际。