【发布时间】:2021-03-02 12:06:24
【问题描述】:
当List 内容发生更改时,我遇到了与呈现.sheet 相关的SwiftUI 问题。让我详细解释一下情况。
我提供了您可以克隆的a sample example on Github,以便您轻松重现该错误。
上下文
我只有 2 个视图:
PlaylistCreationViewSearchView
他们每个人的视图模型分别称为PlaylistCreationViewModel 和SearchViewModel。
PlaylistCreationView 有一个Add Songs 按钮,女巫将显示SearchView 有一个sheet。当用户在搜索结果中触摸一首歌曲时,SearchView 发送一个 onAddSong 完成处理程序,该处理程序将通知 PlaylistCreationView 一首歌曲已添加。
这里有一个简单的情景模式:
这里也是一些视图的截图:
播放列表创建视图
搜索视图
问题
当用户触摸SearchView 中的歌曲时,SearchView 的内容会被重绘。我的意思是视图被重新创建。如果第一次再次加载该视图,则会显示该视图。就像这样:
为了简化问题,这里是另一种情况的模式:
这是我在触摸一首歌后观察到的:
如您所见,歌曲已正确添加到播放列表,但 SearchView 现在为空白,因为它已被重新创建。
我无法解释的是,为什么 PlaylistCreationViewModel 中的列表更改会导致重新绘制呈现的 sheet。
如何重现问题
我提供了您可以克隆的a sample example on Github。重现问题:
- 克隆项目并在任何 iPhone 模拟器上运行它。
- 触摸“添加歌曲”。
- 在搜索视图顶部的搜索栏中输入内容。
- 选择一首歌曲。您的搜索应该已经消失,因为视图已经重建。
代码
播放列表创建视图模型
final class PlaylistCreationViewModel: ObservableObject {
@Published var sheetType: SheetType?
@Published var songs: [String] = []
}
extension PlaylistCreationViewModel {
enum SheetType: String, Identifiable {
case search
var id: String {
rawValue
}
}
}
播放列表创建视图
struct PlaylistCreationView: View {
@ObservedObject var viewModel: PlaylistCreationViewModel
var body: some View {
NavigationView {
List {
ForEach(viewModel.songs, id: \.self) { song in
Text(song)
}
Button("Add Song") {
viewModel.sheetType = .search
}
.foregroundColor(.accentColor)
}
.navigationTitle("Playlist")
}
.sheet(item: $viewModel.sheetType) { _ in
sheetView
}
}
private var sheetView: some View {
let addingMode: SearchViewModel.AddingMode = .playlist { addedSong in
// This line leads SwiftUI to rebuild the SearchView
viewModel.songs.append(addedSong)
}
let sheetViewModel: SearchViewModel = SearchViewModel(addingMode: addingMode)
return NavigationView {
SearchView(viewModel: sheetViewModel)
.navigationTitle("Search")
}
}
}
搜索视图模型
final class SearchViewModel: ObservableObject {
@Published var search: String = ""
let songs: [String] = ["Within", "One more time", "Veridis quo"]
let addingMode: AddingMode
init(addingMode: AddingMode) {
self.addingMode = addingMode
}
}
extension SearchViewModel {
enum AddingMode {
case playlist(onAddSong: (_ song: String) -> Void)
}
}
搜索视图
struct SearchView: View {
@ObservedObject var viewModel: SearchViewModel
var body: some View {
VStack {
TextField("Search", text: $viewModel.search)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
List(viewModel.songs, id: \.self) { song in
Button(song) {
switch viewModel.addingMode {
case .playlist(onAddSong: let onAddSong):
onAddSong(song)
}
}
}
}
}
}
我很确定我缺少一些 SwiftUI 的东西。但我无法得到它。我以前没有遇到过这样的情况。我在网上找不到任何东西。
任何帮助或建议将不胜感激。提前感谢任何愿意花时间阅读和理解问题的人。我希望我已经足够好地描述了这个问题。
【问题讨论】:
-
您必须使用 100% 纸张吗?我的意思是为什么不使用 CustomView 然后所有问题都解决了,因为工作表有点错误,即使有人在您的代码中发现问题,也可以理解错误并处理它,也许新的拯救不需要Xcode 或 SwiftUI 的更新。我 99% 确定这个问题与您的代码无关,而与工作表有关。
-
@swiftPunk 感谢您的回复。我不必使用床单。但这是在 iOS 应用程序之间导航的标准方式,对用户体验来说是可观的。如果这是一个错误,我会向 Apple 报告。但我想确定这不是我自己的错误。
-
什么是工作表? sheet 只不过是一个显示 View 的动画,你可以通过一些编码来做到这一点,如果不想要代码,那么你需要处理 apple bugy sheet。我对床单有很多经验,他们只是没有准备好充分使用,
-
@swiftPunk 使用工作表对我的主要优势在于我正在构建的多平台应用程序。利用组件的简单性会很棒。现在我必须找到另一个解决方案并将错误报告给 Apple。感谢您的建议。
标签: ios swift swiftui swiftui-list