【问题标题】:How to have a NavigationLink inside another NavigationLink如何在另一个 NavigationLink 中有一个 NavigationLink
【发布时间】:2020-08-24 08:05:27
【问题描述】:

我和我的团队目前正在用 SwiftUI 开发一个 Mastodon 客户端,我有一个简单的 StatusView,用于显示所有帖子数据,目前看起来像这样:

这个视图,在我的项目中称为StatusView,有两个NavigationLinks:主要的一个,将用户重定向到帖子的线程,一个将用户重定向到帖子的作者个人资料,当帖子的个人资料图片时被点击。

到这里为止,一切正常。如果您点击帖子上不是按钮(例如、提升和分享)或个人资料图片的任何地方,它会打开该主题。如果您点击个人资料图片,则会打开作者的个人资料。

但是,如果您点击下方个人资料图片,应用会崩溃,只会出现以下错误:

2020-08-23 21:32:39.929392-0400 Hyperspace[830:147862] WF: _WebFilterIsActive returning: NO
2020-08-23 21:32:40.117865-0400 Hyperspace[830:147862] [assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>
2020-08-23 21:32:40.117994-0400 Hyperspace[830:147862] [ProcessSuspension] 0x11decfa80 - ProcessAssertion: Failed to acquire RBS Background assertion 'WebProcess Background Assertion' for process with PID 837, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}
2020-08-23 21:32:40.119401-0400 Hyperspace[830:147862] [assertion] Error acquiring assertion: <Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}>
2020-08-23 21:32:40.119549-0400 Hyperspace[830:147862] [ProcessSuspension] 0x11decfac0 - ProcessAssertion: Failed to acquire RBS Suspended assertion 'WebProcess Suspended Assertion' for process with PID 837, error: Error Domain=RBSAssertionErrorDomain Code=2 "Specified target process does not exist" UserInfo={NSLocalizedFailureReason=Specified target process does not exist}
Fatal error: UIKitNavigationBridge: multiple active destinations: file SwiftUI, line 0
2020-08-23 21:32:40.292135-0400 Hyperspace[830:147862] Fatal error: UIKitNavigationBridge: multiple active destinations: file SwiftUI, line 0

我猜这是因为当你点击那里时,线程和个人资料的导航链接都被触发,导致应用程序崩溃,因为有多个活动目的地,因为它试图转到线程和个人资料同一时间。

TL;DR

我的应用程序崩溃了,因为两个 NavigationLink 在它们不应该被同时触发的时候被触发了。

我该如何解决这个问题?

提前致谢。

我的代码

/// The status is being displayed in a ``StatusList``, so we should make it smaller and more compact.
private struct CompactStatusView: View {

    /// The ``Status`` data model from where we obtain all the data.
    var status: Status

    /// Used to trigger the navectigationLink to redirect the user to the thread.
    @Binding var goToThread: Bool

    /// Used to redirect the user to a specific profile.
    @Binding var profileViewActive: Bool

    var body: some View {
        ZStack {

            self.content
                .padding(.vertical, 5)
                .contextMenu(
                    ContextMenu(menuItems: {

                        Button(action: {}, label: {
                            Label("Report post", systemImage: "flag")
                        })

                        Button(action: {}, label: {
                            Label("Report \(self.status.account.displayName)", systemImage: "flag")
                        })

                        Button(action: {}, label: {
                            Label("Share as Image", systemImage: "square.and.arrow.up")
                        })

                    })
                )

        }
            .buttonStyle(PlainButtonStyle())
            .navigationBarHidden(self.profileViewActive)
    }

    var content: some View {
        HStack(alignment: .top, spacing: 12) {

            URLImage(URL(string: self.status.account.avatarStatic)!,
                placeholder: { _ in
                    Image("amodrono")
                        .resizable()
                        .scaledToFit()
                        .clipShape(Circle())
                        .frame(width: 50, height: 50)
                        .redacted(reason: .placeholder)
                },
                content: {
                    $0.image
                        .resizable()
                        .scaledToFit()
                        .clipShape(Circle())
                        .frame(width: 50, height: 50)
                }
            )
                .onTapGesture {
                    self.profileViewActive.toggle()
                }
                .background(
                    NavigationLink(
                        destination: ProfileView(
                            accountInfo: ProfileViewModel(
                                accountID: self.status.account.id
                            ),
                            isParent: false
                        ),
                        isActive: self.$profileViewActive
                    ) {
                        Text("")
                    }
                        .frame(width: 0, height: 0)
                )

            VStack(alignment: .leading, spacing: 2) {
                HStack(alignment: .firstTextBaseline) {

                    if !self.status.account.displayName.isEmpty {
                        Text("\(self.status.account.displayName)")
                            .font(.headline)
                            .lineLimit(1)
                    }

                    Text("@\(self.status.account.acct)")
                        .foregroundColor(.secondary)
                        .lineLimit(1)

                    Text("· \(self.status.createdAt.getDate()!.getInterval())")
                        .foregroundColor(.secondary)
                        .lineLimit(1)
                }

                StatusViewContent(
                    isMain: false,
                    content: self.status.content,
                    card: self.status.card,
                    attachments: self.status.mediaAttachments,
                    goToProfile: self.$profileViewActive
                )

                StatusActionButtons(
                    isMain: false,
                    repliesCount: self.status.repliesCount,
                    reblogsCount: self.status.reblogsCount,
                    favouritesCount: self.status.favouritesCount,
                    statusUrl: self.status.uri
                )

            }
                .onTapGesture {
                    self.goToThread.toggle()
                }
                .background(
                    NavigationLink(
                        destination: ThreadView(
                            mainStatus: self.status
                        ),
                        isActive: self.$goToThread
                    ) {
                        EmptyView()
                    }
                )

            Spacer()
        }
    }

}

我想这里的重要部分是:

个人资料图片:

URLImage(URL(string: self.status.account.avatarStatic)!,
                placeholder: { _ in
                    Image("amodrono")
                        .resizable()
                        .scaledToFit()
                        .clipShape(Circle())
                        .frame(width: 50, height: 50)
                        .redacted(reason: .placeholder)
                },
                content: {
                    $0.image
                        .resizable()
                        .scaledToFit()
                        .clipShape(Circle())
                        .frame(width: 50, height: 50)
                }
            )
                .onTapGesture {
                    self.profileViewActive.toggle()
                }
                .background(
                    NavigationLink(
                        destination: ProfileView(
                            accountInfo: ProfileViewModel(
                                accountID: self.status.account.id
                            ),
                            isParent: false
                        ),
                        isActive: self.$profileViewActive
                    ) {
                        Text("")
                    }
                        .frame(width: 0, height: 0)
                )

最后两个修饰符

.onTapGesture {
                    self.goToThread.toggle()
                }
                .background(
                    NavigationLink(
                        destination: ThreadView(
                            mainStatus: self.status
                        ),
                        isActive: self.$goToThread
                    ) {
                        EmptyView()
                    }
                )

【问题讨论】:

    标签: ios swiftui uikit swiftui-navigationlink


    【解决方案1】:

    这里是一些复制场景的可能解决方案的演示(因为提供的代码不能按原样测试)。这个想法是重用一个 NavigationLink,但根据激活位置不同的目的地。

    使用 Xcode 12 / iOS 14 测试

    struct DemoRowView: View {
        @State private var isProfile = false
        @State private var isActive = false
        var body: some View {
            HStack {
                Image(systemName: "person")
                    .scaledToFit()
                    .onTapGesture {
                        self.isProfile = true
                        self.isActive = true
                    }
                Text("Thread description")
                    .onTapGesture {
                        self.isProfile = false
                        self.isActive = true
                    }
                    .background(
                        NavigationLink(destination: self.destination(), isActive: $isActive) { EmptyView() }
                    )
            }
            .buttonStyle(PlainButtonStyle())
        }
    
        @ViewBuilder
        private func destination() -> some View {
            if isProfile {
                ProfileView()
            } else {
                ThreadView()
            }
        }
    }
    

    【讨论】:

    • 谢谢!多么简单的解决方案,我不能再笨了......?
    猜你喜欢
    • 2020-03-31
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    相关资源
    最近更新 更多