SwiftUI 工作表中未触发深层链接 onChange

Posted

技术标签:

【中文标题】SwiftUI 工作表中未触发深层链接 onChange【英文标题】:Deep link onChange not triggered in SwiftUI sheet 【发布时间】:2020-10-08 08:19:52 【问题描述】:

我的 SwiftUI 应用中的深层链接存在问题。

在我的应用程序类中,我已将 deepLink 声明为层次结构中 ContentView() 下每个视图的环境变量:

...

@main
struct TestApp: App 

var userSettings: UserSettings
var dataFetcher: DataFetcher
var dataUpdater: DataUpdater

@State var deepLink = ""

init() 
    userSettings = UserSettings()
    dataFetcher = DataFetcher(userSettings: userSettings)
    dataUpdater = DataUpdater(userSettings: userSettings)


var body: some Scene 
    WindowGroup 
        ContentView()
                .environmentObject(userSettings)
                .environmentObject(dataFetcher)
                .environmentObject(dataUpdater)
                .onOpenURL  url in
                    deepLink = url.absoluteString
                
                .environment(\.deepLink, deepLink)
    

在我的 ContentView() 中,我将 deepLink 声明为环境变量

struct ContentView: View 

    ...

    @State var isTestSheetViewPresented = false

    @Environment(\.deepLink) var deepLink: String

    ...

    var body: some View 

        Button(action: 
            self.isTestSheetViewPresented = true
        , label: 
            HStack 
                Spacer()
                Image(systemName: "plus")
                Text("Add")
                Spacer()
            
        )
        .sheet(isPresented: $isTestSheetViewPresented, content: 
            TestSheetView(isPresented: self.$isTestSheetViewPresented)
        )
        .onChange(of: self.deepLink)  _ in
            self.isTestSheetViewPresented = true
        
    


而TestSheetView是这样的

struct TestSheetView: View 

    @Environment(\.deepLink) var deepLink: String

    @State var url: String = ""

    var body: some View 
        Text(url)
            .onChange(of: deepLink)  _ in
                if deepLink != "" 
                    self.url = deepLink
                
            
    

问题是,当我点击一个链接并打开我的应用程序时,TestSheetView 会正确显示,但除非我向下滚动一点,否则不会触发 onChange。

相反,如果我将 TestSheetView 的相同代码放在 ContentView 中,则文本会正确显示

【问题讨论】:

似乎是时间问题。在初始化 TestSheetView 时,body 是在 deepLink 更改之后创建的,因此它无法检测到它。解决方案可能是您在TestSheetView 中使用onAppear 并从那里读取,或者您从ContentView 传入deepLink。如果您需要完整的解决方案,请告诉我。 @George_E 啊,是时间问题。添加 onAppear() 修复它!如果您想发布答案,我会将其标记为解决方案。谢谢 谢谢 - 也只是一个小评论,而不是deepLink != "",最好使用!deepLink.isEmpty。不仅仅是为了可读性,还有性能,虽然差别不会很大。 【参考方案1】:

似乎是时间问题。在初始化 TestSheetView 时,主体是在 deepLink 更改之后创建的,因此它无法检测到它。

解决方案是在TestSheetView 中使用onAppear 并从那里读取,如下所示:

struct TestSheetView: View 

    @Environment(\.deepLink) var deepLink: String

    @State var url: String = ""

    var body: some View 
        Text(url)
            .onAppear 
                if deepLink != "" 
                    self.url = deepLink
                
            
    

【讨论】:

【参考方案2】:

同时处理视图尚未出现的情况和链接正在视图中导航的情况都是不符合人体工程学的。以下视图修饰符处理这两种情况。它假定***导航视图中的 .onOpenURL() 处理程序设置当前选项卡选择以及 currentDeepLink 环境值。

struct DeepLinkViewModifier: ViewModifier 
    @Environment(\.currentDeepLink) private var currentDeepLink
    let action: ((URL) -> Bool)

    func body(content: Content) -> some View 
        content
            .onAppear 
                if let url = currentDeepLink.wrappedValue,
                    action(url) 
                    currentDeepLink.wrappedValue = nil
                
            
            .onOpenURL  url in
                _ = action(url)
            
    


extension View 
    func onDeepLink(perform action: @escaping ((URL) -> Bool)) -> some View 
        return self.modifier(DeepLinkViewModifier(action: action))
    

用途:

struct SomeView: View 
    @State urlString: String = ""

    var body: some View 
        Text(urlString).onDeepLink  url
            self.string = url.absoluteString
            return true // return false if another handler should consume
        
    


struct ContentView: View 
    @State private var tabSelection: TabSelection = .something
    @State private var currentDeepLink: URL? = nil

    var body: some View 
        TabView(selection: self.$tabSelection) 
        ...
        
        .onOpenURL  url in
             self.tabSelection = ... // determine selection from URL
             self.currentDeepLink = url
        
        .environment(\.tabSelection, self.$tabSelection)
        .environment(\.currentDeepLink, self.$currentDeepLink)
    

【讨论】:

谢谢,我试试看。但是,非常聪明的解决方案! 仅供参考,我确实在让它可靠地工作时遇到了一些麻烦,有时两个处理程序都会被调用。最后,我发现最好在当前选项卡中处理 URL。此外,您需要检查当前视图是否显示和/或可见,以避免触发多个 onOpenURL 处理程序。

以上是关于SwiftUI 工作表中未触发深层链接 onChange的主要内容,如果未能解决你的问题,请参考以下文章

轻按即可从 SwiftUI 小部件执行深层链接

当 ObservedObject 更改时,在 SwiftUI 视图中未调用 onReceive

已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数

如果应用程序已通过深层链接打开,Android 深层链接将不起作用

组合框更改事件正在触发工作表中的任何更改

在 iOS 上配置 Firebase 应用后,Branch.io 深层链接停止工作