Mis*_*cha 5 editmode ios swift swiftui swiftui-navigationlink
MyView我有一个导航链接,当根据编辑模式(或任何其他条件)点击其标签 ( ) 时,我需要不同的行为:
DetailView所选模型。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)
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是 if- 和 else- 分支中的视图具有不同的类型(由于修饰符onTapGesture),并且 SwiftUI 不会将它们识别为相同的视图。因此,动画无法插值并且无法正常工作。此外,每次切换MyView时总是会丢失其状态。editMode
(Chris Eidhof 对为什么会发生这种情况做了很好的解释:https://www.objc.io/blog/2021/08/24/conditional-view-modifiers/)
所以我继续将 if 语句移动到onTapGesture修饰符内,如下所示,这样我就不会有两个不同的MyViews:
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)
}
Run Code Online (Sandbox Code Playgroud)
问题是,现在要求#1 不再起作用:onTapGesture完全吞没点击手势,因此导航链接永远不会被触发以显示DetailView. 说得通。
现在我的问题是:
简而言之,你想要改变:
if editMode == .active {
MyView()
.onTapGesture {
editingModel = model
}
} else {
MyView()
}
Run Code Online (Sandbox Code Playgroud)
进入:
MyView()
.allowsHitTesting(editMode == .active)
.onTapGesture {
editingModel = model
}
Run Code Online (Sandbox Code Playgroud)
这解决了这个问题,因为现在onTapGesture只有当它实际上可以监听触摸时才会触发。它只能在 时触发editMode == .active,否则命中测试将被禁用。
完整示例:
struct ContentView: View {
@State private var displayedItem: String?
@State private var editingModel: EditingModel?
@State private var editMode: EditMode = .inactive
var body: some View {
NavigationView {
List {
Button("Edit mode: \(editMode == .active ? "active" : "inactive")") {
if editMode == .active {
editMode = .inactive
} else {
editMode = .active
}
}
NavigationLink(tag: "model", selection: $displayedItem) {
Text("DetailView")
} label: {
if editMode == .active {
MyView()
.onTapGesture {
editingModel = EditingModel(tag: "model")
}
} else {
MyView()
}
}
.sheet(item: $editingModel) { model in
Text("EditingView: \(model.tag)")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
struct MyView: View {
var body: some View {
Text("MyView")
.frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle())
}
}
Run Code Online (Sandbox Code Playgroud)
struct EditingModel: Identifiable {
var id: String { tag }
let tag: String
}
Run Code Online (Sandbox Code Playgroud)
将内部标签位更改为:
MyView()
.allowsHitTesting(editMode == .active)
.onTapGesture {
editingModel = EditingModel(tag: "model")
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3623 次 |
| 最近记录: |