Swift

SwiftUI:Swift协议

2021-01-25  本文已影响0人  猪猪行天下

就像其他Swift框架一样,SwiftUI严重依赖协议作为其定义的核心部分。
在这篇新文章中,我们来看看Swift标准库协议在SwiftUI中的使用:Hashable, Identifiable, 和 Equatable

Equatable

Equatable是SwiftUI中重要的协议之一。计算布局、绘制组件等都很消耗性能的,SwiftUI通过减少绘制操作来提高性能。

SwiftUI使用Equatable来做出这样的决定:即使对于没有声明Equatable一致性的视图,SwiftUI也会通过快速反射来遍历视图定义,检查每个属性的公平性,并据此决定是否需要重新绘制。

更深入的可以查看Equatable背后的奥秘

Identifiable

Equatable用于检测视图状态变化(因此触发重绘)时,Identifiable将视图标识与其状态分离。
例如在SwiftUI中,它用于跟踪ListOutlineGroup中元素的顺序:

另外一个是IdentifiablePicker中使用的例子:在这种情况下,Identifiable用于确定可能候选元素中的哪个元素是被选中的(如果有的话),而不考虑元素类型定义中的其他可能状态。

最后,Identifiable被系统的alerts/sheets使用如下:

所有这些都提供了一个更简单的isPresented boolean替代方案。

使用Identifiable让我们不仅有机会清晰地定义可能的不同的alerts/sheets,,而且还可以在需要时传递更多数据。

想象一下有两个不同的sheets:

enum ContentViewSheet: Identifiable {
  case one
  case two

  var id: Int {
    switch self {
    case .one:
      return 1
    case .two:
      return 2
    }
  }
}

ContentViewSheet为每个sheet都有一个case,我们可以这样定义sheet(item:onDismiss:content:):

struct ContentView: View {
  @State private var showingSheet: ContentViewSheet?

  var body: some View {
    VStack {
      Button("go to sheet 1") {
        showingSheet = .one
      }

      Button("go to sheet 2") {
        showingSheet = .two
      }
    }
    .sheet(item: $showingSheet, content: presentSheet)
  }

  @ViewBuilder
  private func presentSheet(for sheet: ContentViewSheet) -> some View {
    switch sheet {
    case .one:
      Text("One")
    case .two:
      Text("Two")
    }
  }
}

该视图显示了几个按钮,当点击这些按钮时,将触发相关工作表sheet的显示:

sheet.gif

假设我们想要传递一个值给第二个sheet表单,这样做的方法(可能是不推荐的)是通过扩展第二个ContentViewSheet的case的关联值:

enum ContentViewSheet: Identifiable {
  case one
  case two(someData: Int) // new associated value

  /// The identity ignores the `someData` value.
  var id: Int {
    switch self {
    case .one:
      return 1
    case .two:
      return 2
    }
  }
}

有了someData,我们现在可以在创建新sheet表时传递一个Int值(或者任何其他值):

struct ContentView: View {
  ...

  var body: some View {
    VStack {
      ...

      Button("go to sheet 2") {
        showingSheet = .two(someData: Int.random(in: 1...5)) // Pass data here
      }
    }
    .sheet(item: $showingSheet, content: presentSheet)
  }

  @ViewBuilder
  private func presentSheet(for sheet: ContentViewSheet) -> some View {
    switch sheet {
      ...
    case .two(let value): // read and use the data here
      Text("Sheet two with value \(value)")
    }
  }
}
sheet2.gif

Hashable

Hashable主要用于两个视图:TabViewNavigationLink

让视图使用tag标签,是我们将视图声明连接到swiftUI需要监听的相关离散类型值的方式。

TabView的case中,我们可以如下声明每个可能的选项卡:

enum Tab: Hashable {
  case home
  case view2
  case view3
  case view4
}

除了类型声明之外,我们现在还需要一种方法来将每个视图与每个选项卡关联起来,这是通过tag(_:)方法实现的:

struct ContentView: View {
  @State private var tabBarState: Tab = .home

  var body: some View {
    TabView(selection: $tabBarState) {
      Text("Home")
        .tabItem { Text("Home") }
        .tag(Tab.home)

      Text("View 2")
        .tabItem { Text("View 2") }
        .tag(Tab.view2)

      Text("View 3")
        .tabItem { Text("View 3") }
        .tag(Tab.view3)

      Text("View 4")
        .tabItem { Text("View 4") }
        .tag(Tab.view4)
    }
  }
}
tab.gif

以类似的方式,我们为每个可能的目标声明一个新的NavigationLink:

enum ContentViewNavigation: Hashable {
  case a // destination a
  case b // destination b
  case c // destination a
}

struct ContentView: View {
  @State var showingContent: ContentViewNavigation?

  var body: some View {
    NavigationView {
      VStack {
        NavigationLink("Go to A", destination: Text("A"), tag: .a, selection: $showingContent)
        NavigationLink("Go to B", destination: Text("B"), tag: .b, selection: $showingContent)
        NavigationLink("Go to C", destination: Text("C"), tag: .c, selection: $showingContent)
      }
    }
  }
}
destination.gif

虽然这种标签方法对TabView来说是完全有意义的,但由于NavigationLink的存在,这也是目前在应用程序中控制导航的最先进的方法。当我们想要将数据传递到目标视图时,这就变得很麻烦了,尤其是通过编程的方式(深度链接,有人知道吗?)

这可能是从UIKit到SwiftUI最尴尬的地方,我相信SwiftUI团队选择这条路线只是为了导航,而不是其他所有视图演示中使用的Identifiable方法(如上所示),但我也希望我们在未来能看到一些改进。

总结

就像我们需要掌握和理解Objective-C,如何真正理解UIKit一样,学习和理解SwiftUI也需要我们去学习和理解Swift:我们对其中一个了解的越多,对另一个的了解也就越多。

上一篇 下一篇

猜你喜欢

热点阅读