SwiftUI:切换选项卡时工作表演示同步问题

问题描述 投票:0回答:1

在我的 SwiftUI 应用程序中,我有一个 tabView,其中包含两个呈现相同视图的选项卡。每个视图中的内容在各自的视图中规定。这些视图有一个 .sheet 修饰符,当前基于

@Published var showSheet
类中定义的
ObservableObject
触发。

我看到的问题发生在以下情况:

  1. 导航至上述选项卡之一
  2. 点击所选选项卡视图中的按钮,触发 .sheet
  3. 关闭表格
  4. 导航到第二个提到的选项卡,它显示相同的视图(不同的数据)
  5. 点击触发 .sheet 的按钮

点击按钮后,工作表会弹出,但随后会立即消失,无需用户交互。

目标是让工作表正常打开和关闭,同时也能够正常切换选项卡。

在我看来,

triggerSheet
是在到达新标签时出现的,但我不明白为什么。我能够使用类似于下面的代码的内容重现该问题,希望我想要完成的任务的想法很清楚。

代码:

标签视图:

struct TabView: View {
    @StateObject private var obsPresentation = ObsPresentation.shared
    
    var body: some View {
            ZStack {
                VStack {
                    TabView(selection: $obsPresentation.currentTab) {
                            if obsPresentation.conditionOne {
                                HealthView()
                                    .tabItem {
                                        Label("Person 1 Health", systemImage: "heart")
                                    }
                                    .tag(obsPresentation.Tab.health1)
                            }
                            
                            if obsPresentation.conditionTwo {
                                HealthView()
                                    .tabItem {
                                        Label("Person 2 Health", systemImage: "heart")
                                    }
                                    .tag(obsPresentation.Tab.health2)
                            }
                    }
                }
            }
    }
}

健康视图:

struct HealthView: View {
    @StateObject private var obsPresentation = ObsPresentation.shared
    
    var body: some View {
        VStack() {
            ScrollView {
                LazyVGrid() {
                    ForEach(...) { _ in
                        Button(action: {
                            obsPresentation.showSheet()
                        }) {
                            ... UI
                        }
                    }
                }
            }
        }
        .sheet(isPresented: $obsPresentation.triggerSheet) {
            SheetView()
        }
    }
}

观察对象类:

public class ObsPresentation: ObservableObject {
    public static var shared = ObsPresentation()
    
    public enum Tab {
        case health1, health2
    }
    
    @Published public var currentTab: Tab = .health1 {
        didSet {
            switch tabSelection {
            case .health1:
                ...
            case .health2:
                ...
            default: break
            }
        }
    }
    
// These conditions are manipulated elsewhere
    @Published public var condition1 = true 
    @Published public var condition2 = true
    
    @Published var triggerSheet = false

    func showSheet() {
        triggerSheet = true
    }
}

这里显而易见的答案是将绑定sheetTrigger bool 本地化为HealthView() 作为适用于工作表演示的

@State var
。但是,我的应用程序还支持深度链接,某些特定链接需要导航到选项卡并立即打开工作表。因此,sheetTrigger bool 必须可以在视图外部访问,以便可以通过深度链接逻辑进行切换。

我还尝试创建一个单独的

ObservableObject
类,其方式与
ObsPresentation
类似,仅处理基于工作表的代码。这导致了同样的行为。

谢谢你

swift swiftui swiftui-tabview
1个回答
0
投票

主要问题是您使用的是

shared
状态对象,该对象设置为
true
,并且根据您提供的代码从未设置为
false
。这意味着当您第一次呈现该工作表时,它会以您期望的方式运行,但是当您第二次呈现该工作表时,它只会短暂呈现然后被忽略,因为您已在第二次有效地将布尔值切换为
false
按钮。看起来像这样,按执行顺序;初始化
false
-> 点击按钮 -> 设置
true
-> 工作表呈现 -> 工作表消失 -> 点击第二个按钮 -> 设置
false
-> 奇怪的行为。

所以,如果您已经读到这里,那么您肯定想知道,既然该工作表设置为

false
,为什么它甚至会出现。这是因为工作表具有独特的行为,它们在动画中期时会忽略某些线程操作。您的实现正在触发工作表出现,因为
@State
正在更新,并且在
ViewBuilder
的上下文中,它不关心它是
true
还是
false
,只是它已更新,并且应该重新绘制。然而,当它处于重新绘制的中间时,它的发布值翻转为 false,从而导致工作表消失。通过从父级中解雇工作表的父级,同时提供一个工作表作为证明,也可能会发生类似的奇怪行为。那么如何解决呢?

修复工作表(尤其是用于不同用途的工作表)的最佳方法是使用

Enum
代替布尔值。例如:

enum PresentedSheet {
    case sheetOne, sheetTwo, sheetThree
}

如果您要使用可选值,那么只要该值不为零,您就可以显示工作表。例如:

@State presentedSheet: PresentedSheet? = nil

var body: some View {
    Text("Example")
        .sheet(item: $presentedSheet) {
            switch presentedSheet { //Show the view you want }
        }
}

在您的情况下,您可以在可观察对象上添加

presentedSheet
代替布尔值。如果您需要其他控件,如果您需要在该工作表关闭时了解或更新某些内容,可以调用回调函数
onDismiss

最后一点,在使用工作表时,如果您在不同视图之间共享工作表,请确保从最父视图中显示该工作表,或者如果特定的子视图被销毁,它也会自动消除您当前的工作表。提交的表。另外,不要过度使用它,因为它会很快使您的代码变得混乱或使事情变得复杂。

© www.soinside.com 2019 - 2024. All rights reserved.