当前位置: 首页 > 知识库问答 >
问题:

SwiftUI MVVM协调器/路由器/导航链接

卫君博
2023-03-14

我在将UIKit架构模式转换为SwiftUI时遇到了问题。我当前的模式主要是带有协调器/路由器的MVVM。MVVM部分似乎相当容易和自然,添加了@observableobject/@published。但是协调/路由似乎并不直观。视图和协调(导航)功能在SwifTUI中紧密耦合。除了使用帮助器结构 之外,似乎不可能将它们分开。

这里有一个例子:我想在SwiftUI中创建一个可重用的row/cell。假设生产中的这一行非常复杂,因此我想重用它。我想把它也放在另一个模块中,这样我就可以在多个目标中重用它。(如iOS,macCatalyst等)

现在我想控制当用户点击那个视图或那个视图中的按钮时会发生什么。根据上下文,我需要导航到不同的目的地。就我所知,可能的NavigationLink目标必须硬连接到视图中,或者必须将 传递到视图中。

这里有一些示例代码。此单元格/行包含两个按钮。我希望导航到其他视图,这些视图依赖于上下文,而不是硬连接到代码中:

struct ProductFamilyRow: View {
    @State private var selection: Int? = 0
    let item: ProductFamilyItem

    let destinationView1: AnyView
    let destinationView2: AnyView

    var body: some View {
        VStack {
            NavigationLink(
                destination: destinationView1,
                tag: 1,
                selection: self.$selection
            ) {
                EmptyView()
            }

            NavigationLink(
                destination: destinationView2,
                tag: 2,
                selection: self.$selection
            ) {
                EmptyView()
            }

            HStack {
                Text(item.title)
                Button("Destination 1") {
                    self.selecthtml" target="_blank">ion = 1
                }.foregroundColor(Color.blue)

                Button("Destination 2") {
                    self.selection = 2
                }.foregroundColor(Color.blue)
            }

            //Image(item.image)
        }.buttonStyle(PlainButtonStyle())
    }
}

这似乎是SwiftUI的一大设计缺陷。除了使用 hack之外,带有导航链接的可重用组件基本上是不可能的。据我所知, 只用于需要type-erasure的特定用例,并且有相当多的性能缺陷。因此,我认为这不是使用SwiftUI创建可重用,可导航视图的惯用解决方案。

这真的是唯一的解决办法吗?也许我完全错了,这是一个错误的方向。我在什么地方读过(再也找不到邮报了)关于使用一些中央状态来指示显示哪个视图,但是我没有看到具体的例子。

第二个挑战:我也不希望细胞对任何其他的点击,然后对按钮作出反应。但似乎不可能控制细胞的定位。(因此不是点击其中一个按钮,而是在单元格中的任何地方)在当前示例代码中,它(出于任何原因)导航到“destination 2”。

提前谢谢你。

共有1个答案

余靖
2023-03-14

最好为您的行使用泛型,如下所示(用Xcode11.4测试)

用法示例:

ProductFamilyRow(item: ProductFamilyItem(title: "Test"),
    destinationView1: { Text("Details1") },
    destinationView2: { Text("Details2") })

接口:

为行突出显示添加更新的块。列表具有自动检测行内按钮或链接的功能,如果存在任何标准(键),则突出显示。因此,要禁用这种行为,它需要隐藏自定义按钮样式下的所有内容。

struct ProductFamilyRowStyle: ButtonStyle {

    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .colorMultiply(configuration.isPressed ? 
                 Color.white.opacity(0.5) : Color.white) // any effect you want
    }
}

struct ProductFamilyRow<D1: View, D2: View>: View {
    let item: ProductFamilyItem
    let destinationView1: () -> D1
    let destinationView2: () -> D2

    init(item: ProductFamilyItem, @ViewBuilder destinationView1: @escaping () -> D1,
        @ViewBuilder destinationView2: @escaping () -> D2)
    {
        self.item = item
        self.destinationView1 = destinationView1
        self.destinationView2 = destinationView2
    }

    @State private var selection: Int? = 0

    var body: some View {
        VStack {
            HStack {
                Text(item.title)
                Button(action: {
                    self.selection = 1
                }) {
                    Text("Destination 1")
                        .background( // hide link inside button !!
                            NavigationLink(destination: destinationView1(),
                                tag: 1, selection: self.$selection) { EmptyView() }
                        )
                }.foregroundColor(Color.blue)

                Button(action: {
                    self.selection = 2
                }) {
                    Text("Destination 2")
                        .background(
                            NavigationLink(destination: destinationView2(),
                                tag: 2, selection: self.$selection) { EmptyView() }
                        )
                }.foregroundColor(Color.blue)
            }

            //Image(item.image)
        }.frame(maxWidth: .infinity) // to have container centered
        .buttonStyle(ProductFamilyRowStyle())
    }
}
 类似资料:
  • 问题内容: 我在将UIKit架构模式转换为SwiftUI时遇到问题。我目前的模式主要是带有协调器/路由器的MVVM。通过添加@ ObservableObject / @ Published,MVVM部分看起来非常简单自然。但是,协调/路由似乎并不直观。视图和协调(导航)功能在SwiftUI中紧密结合在一起。似乎实际上不可能将它们与使用helper结构分开。 这里是一个示例:我想在SwiftUI中创

  • 路由管理 路由管理主要是为了实现页面切换。Flutter中,页面称为路由Router,由导航器Navigator控制,导航器维护一个路由栈,路由入栈(push)则打开新页面,路由出栈(pop)则关闭页面。Flutter中的页面切换就是导航器指挥路由入栈出栈的过程,即:Navigator来push/pop页面Route的过程。写写常用场景的demo。 页面跳转 核心方法:Navigator.push

  • 嗨,我不确定这是一个期望的行为还是一个bug。 这是一个空的create react应用程序示例,带有 版本: 反应:^16.13.1, react-dom:^16.13.1, react-router-dom:^5.2.0, 反应脚本:3.4.1 部件: /-对于主部件 /触点-用于触点组件 这里提供小提琴 多次单击“主页”链接会显示一条

  • 我目前有一个react应用程序,我正在工作,路由是错误的。我以前已经像这样设置了react应用程序及其路由,但是当试图路由到“details”组件时,只有url发生了变化,但是组件没有加载。多一双眼睛就能看到我错过了什么。我将路线设置为: < li>index.js: 根“/”路径组件加载,但我无法获取详细信息组件组件在使用history进行路由时呈现.

  • 在阅读了Akka的文档和网上的一些帖子之后,我仍然对路由器和调度器之间的关系没有一个清楚的认识。 1)路由器是否总是使用dispatcher向路由进行调度?路由器是否可以不使用dispatcher完成其工作? 2)如果配置中没有定义额外的调度器,我的理解是将使用默认调度器。在我的actor系统中,我有一个集群,其中有两个生产者actor使用路由器actor和三个消费者actor。生产者和消费者都运

  • 我正在尝试在我的nginx服务器上设置vue路由器。我遇到的问题是,如果我直接在浏览器中输入url,我的路线就不起作用。 我尝试了vue路由器文档中描述的服务器配置,以及建议的堆栈溢出类似配置。我当前的nginx位置配置如下: 所做的就是将任何路径重定向到我的根组件(path:),而不是。这确实有意义,并且似乎只重定向到索引文件。我如何重定向直接链接的到路由在我的VueJS应用程序? 以下是我的v

  • 我正在结合Vuex和vue路由器构建Vuetify应用程序。一些视图使用默认的导航抽屉,但其他视图的导航抽屉中有不同的项。这篇文档说我可以通过道具来查看组件。所以我这样实现它: 但显然, 但是<代码>

  • 我正在使用React路由器与链接,以改变URL和导航通过应用程序。在阅读列表中,我使用以下代码导航用户阅读edit: 我定义了以下路由: 我怎样才能解决那个问题?