繁体   English   中英

Combine 框架的基本使用

[英]Basic use of the Combine Framework

Swift 5.2 iOS 14

试图了解 SwiftUI 中的 Combine Framework 并使用我在 web 上找到的示例将此代码放在一起。但是...示例不完整。

现在,当我改变我的设备的方向时,它会写入方向,但我如何在我的主循环中使用它? 我似乎也找不到任何要订阅的东西,所以我尝试只使用 onChange。 可悲的是,这是行不通的。

class SizeClassViewV: ObservableObject {
  @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
  @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?

  enum Orientation {
    case portrait
    case landscape
  }
  @Published var orientation: Orientation = .portrait
  private var listener: AnyCancellable?

  init() {
    if horizontalSizeClass == .compact && verticalSizeClass == .regular {
      orientation = .portrait
    } else if horizontalSizeClass == .regular && verticalSizeClass == .compact {
      orientation = .landscape
    }
    listener = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
        .compactMap { ($0.object as? UIDevice)?.orientation }
        .compactMap { deviceOrientation -> Orientation? in
            if deviceOrientation.isPortrait {
                return .portrait
            } else if deviceOrientation.isLandscape {
                return .landscape
            } else {
                return nil
            }
        }
        .assign(to: \.orientation, on: self)
  }

  deinit {
    listener?.cancel()
  }
}

在我的主循环中现在看起来像这样吗?

struct ContentView: View {
@State var orient = SizeClassViewX()
var body: some View {
  Text("foo")
    .onChange(of: orient.orientation) { ( _ ) in
      print("changed")
    }
  }
}

当我改变方向时从不打印改变?

final class SizeClassViewV: ObservableObject {
  enum Orientation: Equatable {
    case portrait
    case landscape
  }

  @Published var orientation: Orientation = .portrait

  private var listener: AnyCancellable?

  init() {
    orientation = UIDevice.current.orientation.isPortrait ? Orientation.portrait : .landscape
    listener = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
      .compactMap { ($0.object as? UIDevice)?.orientation }
      .map { $0.isPortrait ? Orientation.portrait : .landscape }
      .assign(to: \.orientation, on: self)
  }

  deinit {
    listener?.cancel()
  }
}
struct ContentView: View {
  @ObservedObject var orient  = SizeClassViewV()

  var body: some View {
    Text("Hello, world!")
      .padding()
      .onReceive(orient.$orientation) { value in
        print(value)
      }
  }
}

我似乎找不到要订阅的内容

如果你看一下onReceive声明,你可以看到它接受一个 Combine Publisher

@inlinable public func onReceive<P>(_ publisher: P, perform action: @escaping (P.Output) -> Void) -> some View where P : Publisher, P.Failure == Never

这意味着如果你想订阅组合方式的orientation变化,你可以只使用onReceive并传递相关的Publisher

struct ContentView: View {
    @State var orient = SizeClassViewV()
    var body: some View {
        Text("foo")
            .onReceive(orient.$orientation) { _ in
                print("changed")
            }
    }
}

它实际上以不同的方式工作 - Environment包装器用于 SwiftUI 视图的上下文,因此请按以下演示使用:

struct ContentView: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    
    var body: some View {
        Text("foo")
            .onChange(of: horizontalSizeClass) { _ in
                print("horizontal class changed")
            }
            .onChange(of: verticalSizeClass) { _ in
                print("vertical class changed")
            }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM