(仅在macOS上尝试过,但我相信iOS上的行为相同)
macOS 10.15.2(19C57); Xcode:11.3(11C29)
(由于我在问题中发现了新的关系,所以对问题进行了更新)
我有以下代码:
List(model.filteredStatus) { status in
StatusViewRow(status: status, model: self.model)
.contextMenu{
Text("menu 1")
Text("menu 2")
}
}
效果很好。
但是如果我想改用ForEach(无论为什么):
ForEach(model.filteredStatus) { status in
StatusViewRow(status: status, model: self.model)
.contextMenu{
Text("menu 1")
Text("menu 2")
}
}
上下文菜单不出现。
我已找到原因。原因是ForEach
+ contextMenu
+ if
语句组合的错误工作!
ContextMenu在if
语句内的行的一部分上无法正常工作。当我使用List
时,在ForEach
的ful行上效果很好,并且仅在wegle行的部分上效果很好。
有人可以解释为什么吗?
我在if
的contextMenu中有一条StatusViewRow
语句未在此部分显示:
struct StatusViewRow : View {
@ObservedObject var status : FileStatusViewModel
@ObservedObject var model : StatusViewModel
var body: some View {
HStack {
TaoToggle(state: status.stageState) { self.status.toggleStageState() }
// you can replace to just a toogle
// ISSUE START HERE
if(model.fileNamesOnly) {
StyledText(verbatim: status.fileName )
.style(.highlight(), ranges: { [$0.lowercased().range(of: model.filterStr.lowercased() )]})
}
else {
StyledText(verbatim: status.path )
.style(.foregroundColor(.gray), ranges: { [$0.range(of: status.fileDir) ] } )
.style(.bold(), ranges: { [$0.range(of: status.fileName) ] })
.style(.highlight(), ranges: { [$0.lowercased().range(of: model.filterStr.lowercased() )]})
}
// ISSUE END HERE
}
}
}
答案 0 :(得分:0)
您需要将ForEach
包装在List
或relevant中。
任何包含Text("...")
的视图都必须位于VStack
,HStack
,ZStack
等内部或List
中。否则不会渲染。
创建SwiftUI视图时,协议定义我们需要返回“
some View
”。单词“some
”表示我们正在处理一个不透明的结果类型。这是一项新功能added in Swift 5.1。不透明的结果类型意味着我们必须返回一个且只能返回指定类型的一种,在这种情况下,该类型必须符合“View
”协议。
ForEach
conforms至Hashable
:
struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable
...而stacks(在这种情况下为VStack
)符合View
:
@frozen struct VStack<Content> where Content : View
...以及List
和conforms至View
:
struct List<SelectionValue, Content> where SelectionValue : Hashable, Content : View
所以您需要这样的东西:
ForEach (model.filteredStatus) { status in
VStack { // stack View
StatusViewRow(status: status, model: self.model)
.contextMenu {
Text("Menu 1")
Text("Menu 2")
}
}
}
OR:
ForEach (model.filteredStatus) { status in
StatusViewRow(status: status, model: self.model)
.contextMenu {
VStack { // stack View
Text("Menu 1")
Text("Menu 2")
}
}
}
OR:
List { // List works because it conforms to View
ForEach (model.filteredStatus) { status in
StatusViewRow(status: status, model: self.model)
.contextMenu {
Text("Menu 1")
Text("Menu 2")
}
}
}
本文很好地解释了why的必要性。