当其标签( myView
)被取决于编辑模式(或任何其他条件)时,我需要不同的行为
- 我有一个导航链接, 编辑模式,我想触发导航链接,并使用选定的模型显示
lidetview
。
- 如果我们处于编辑模式,我不想触发导航链接,而是在模态表中显示
editingview
。
这是一种实现我提出的方法的方法:
NavigationLink(tag: model, selection: $displayedItem) {
DetailView(model: model)
} label: {
if editMode == .active {
MyView()
.onTapGesture {
editingModel = model
}
} else {
MyView()
}
}
.sheet(item: $editingModel) { model in
EditingView(model: model)
}
这种方法的问题是,IF-和其他分支中的视图不同(由于 ontapgesture
modifier)和Swiftui并不认为它们是相同的观点。因此,动画不能被插值并且无法正常工作。另外, myview
每次切换 editmode
总是会失去其状态。
(这是克里斯·埃德霍夫(Chris Eidhof)的一个很好的解释:)
所以我继续前进,并将if-statement移至 ontapgesture
modifier中如下所示,因此我没有两个不同的 myview
s:
NavigationLink(tag: model, selection: $displayedItem) {
DetailView(model: model)
} label: {
MyView()
.onTapGesture {
if editMode == .active { // moved
editingModel = model
} // moved
}
}
}
.sheet(item: $editingModel) { model in
EditingView(model: model)
}
问题是,现在需求#1不再起作用: ontapgesture
完全吞下了点击手势因此,从未触发导航链接以显示详细信息View
。有意义。
现在我的问题是:
如果没有这些弊端,我该如何获得所需的行为?
I have a navigation link and I need a different behavior when its label (MyView
) is tapped depending on the edit mode (or any other condition):
- If we are not in edit mode, I want to trigger the navigation link and show the
DetailView
with the selected model.
- If we are in edit mode, I don't want to trigger the navigation link and show an
EditingView
in a modal sheet instead.
Here's a way to implement this that I came up with:
NavigationLink(tag: model, selection: $displayedItem) {
DetailView(model: model)
} label: {
if editMode == .active {
MyView()
.onTapGesture {
editingModel = model
}
} else {
MyView()
}
}
.sheet(item: $editingModel) { model in
EditingView(model: model)
}
The problem with this approach is that the views in the if- and the else-branch have not the same type (due to the onTapGesture
modifier) and SwiftUI doesn't recognize them as the same view. Thus, animations cannot be interpolated and don't work properly. Also, MyView
always loses its state each time editMode
is toggled.
(Here's a great explanation from Chris Eidhof on why that happens: https://www.objc.io/blog/2021/08/24/conditional-view-modifiers/)
So I went ahead and moved the if-statement inside the onTapGesture
modifier as follows so that I don't have two different MyView
s:
NavigationLink(tag: model, selection: $displayedItem) {
DetailView(model: model)
} label: {
MyView()
.onTapGesture {
if editMode == .active { // moved
editingModel = model
} // moved
}
}
}
.sheet(item: $editingModel) { model in
EditingView(model: model)
}
Problem with this is that now requirement #1 doesn't work anymore: The onTapGesture
completely swallow the tap gesture and thus the navigation link is never trigged to show the DetailView
. Makes sense.
Now my question is:
How can I get the desired behavior without any of these downsides?
发布评论
评论(4)
简而言之,您想要将: 更改
为:
这可以解决问题,因为现在 onTapGesture 仅在实际监听触摸时才会触发。它只能在
editMode == .active
时触发,否则命中测试将被禁用。完整示例:
将内部标签位更改为:
In short, you want to change:
Into:
This fixes the issue because now the
onTapGesture
is only triggered when it can actually listen to touches. It can only trigger wheneditMode == .active
, because otherwise the hit testing is disabled.Full example:
Changing the inner label bit to:
在乔治的建议的基础上,我最终得到了以下自定义修饰符:
像魅力一样工作,这样,我不必指定相同的条件
edingmode == .Active
两次)。强烈建议。Building on George's suggestion, I ended up with the following custom modifier:
Works like a charm and this way, I don't have to specify the same condition
editMode == .active
twice (single source of truth). Highly recommended. ????使用Group来包裹onTapGesture。就是这样。
Use Group to wrap onTapGesture. That's it.
您可以使用自定义修饰符。
}
you can use custom modifier.
}