当前位置: 首页 > 面试题库 >

SwiftUI MVVM协调器/路由器/ NavigationLink

邢乐
2023-03-14
问题内容

我在将UIKit架构模式转换为SwiftUI时遇到问题。我目前的模式主要是带有协调器/路由器的MVVM。通过添加@ ObservableObject / @
Published,MVVM部分看起来非常简单自然。但是,协调/路由似乎并不直观。视图和协调(导航)功能在SwiftUI中紧密结合在一起。似乎实际上不可能将它们与使用helper结构分开AnyView

这里是一个示例:我想在SwiftUI中创建可重用的行/单元。可以说生产中的这一行非常复杂,因此我想重用它。我也希望将其放置在另一个模块中,以便可以在多个目标中重复使用它。(例如iOS,macCatalyst等)

在此处输入图片说明

现在,我想控制当用户点击该视图或该视图中的按钮时发生的情况。根据上下文,我需要导航到不同的目的地。据我所知,可能的NavigationLink目标必须
硬连线 到视图中或AnyView必须传递到视图中。

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

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.selection = 1
                }.foregroundColor(Color.blue)

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

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

这似乎是SwiftUI中的主要设计缺陷。除了使用AnyViewhack
之外,带有导航链接的可重用组件基本上是不可能的。据我所知AnyView,它只用于需要类型擦除的特定用例,并且在性能上有很多缺点。因此,我不认为这是使用SwiftUI创建可重用,可导航视图的惯用解决方案。

这真的是唯一的解决方案吗?也许我完全错了,这始终是错误的方向。我读过某处(找不到该帖子..)有关使用某种中央状态的信息,该状态指示了要显示的视图,但是我没有看到具体的示例如何执行此操作。

第二个挑战:我也不希望单元格对其他任何轻按然后对按钮做出反应。但是似乎无法控制如果点击该单元格导航到的位置。(因此,请不要点击按钮之一,而要在单元格中的任何位置)在当前示例代码中,它(出于任何原因)导航到“目标2”。

提前致谢。


问题答案:

最好在行中使用泛型,如下所示(已通过Xcode 11.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())
    }
}


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

  • anu可以完美与react-router搭配使用。 但强烈建议使用reach router, 这个比react router更好用。 anujs也对它进行改造,让它支持IE8的hashchange reach的官网 https://reach.tech/router resolve: { alias: { react: "anujs", "react-dom":

  • 添加一个自定义的路由器 $prepend = false; Swoole::$php->addRouter(new App\MyRouter, $prepend); 第一个参数为路由器对象,必须实现Swoole\IFace\Router接口 第二个参数如果为true,表示添加到路由表的起始位置,默认为false,表示追加到末尾 底层默认添加了2个路由器Swoole\Router\Rewrite和

  • 路由闭包 绝不 在路由配置文件里书写『闭包路由』或者其他业务逻辑代码,因为一旦使用将无法使用 路由缓存 。 路由器要保持干净整洁,绝不 放置除路由配置以外的其他程序逻辑。 Restful 路由 必须 优先使用 Restful 路由,配合资源控制器使用,见 文档。 超出 Restful 路由的,应该 模仿上图的方式来定义路由。 resource 方法正确使用 一般资源路由定义: Route::res

  • Faygo路由器由 MuxAPI API信息与 httprouter 路由两层构成。这样既满足记录详细API信息的需求,又能够保持真实路由的高性能。 MuxAPI API信息层: 属于预注册路由,对外提供无限层级的路由注册功能,支持树状与链状两种注册形式 记录全部API信息,如请求方法、请求路径、请求参数、API名称、API注意事项、API响应说明、操作链(Handler与Middleware)等

  • 路由器用于路由客户端应用程序并定义应用程序对象的URL表示。 当Web应用程序为应用程序中的重要位置提供可链接,可收藏且可共享的URL时,需要路由器。 下表列出了可用于操作BackboneJS - Router - S.No. 方法和描述 1 extend 它扩展了主干的路由器类。 2 routes 它定义了应用程序对象的URL表示。 3 initialize 它为路由器实例化创建了一个新的构造函