【问题标题】:Deep link onChange not triggered in SwiftUI sheetSwiftUI 工作表中未触发深层链接 onChange
【发布时间】: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。不仅仅是为了可读性,还有性能,虽然差别不会很大。

标签: ios swift swiftui


【解决方案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 处理程序。
    猜你喜欢
    • 2021-12-01
    • 2021-09-30
    • 2018-11-17
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多