如何返回和存储不同类型的视图

时间:2019-12-20 03:16:21

标签: swiftui

我想要

  • MapView按条件更改
  • 存储当前的MapView
  • 当前MapView中的调用方法

这可能吗?


MapViewEnvironment.swift

class MapViewEnvironment: ObservableObject {
  @Published var value1 = "aaa"
  @Published var currentMapCompany = "apple"
}

MapViewProtocol.swift

protocol MapViewProtocol {
  func aaa()
  func bbb()
}

AppleMapView.swift

struct AppleMapView: UIViewRepresentable, MapViewProtocol {
  func aaa() { print("AppleMapView - aaa") }

  func bbb() { print("AppleMapView - bbb") }
}

GoogleMapView.swift

struct GoogleMapView: UIViewRepresentable, MapViewProtocol {
  func aaa() { print("GoogleMapView - aaa") }

  func bbb() { print("GoogleMapView - bbb") }
}

CommonMapView.swift

struct CommonMapView: View {
  @EnvironmentObject var mapViewEnvironment: MapViewEnvironment
  @State var cancellable = Set<AnyCancellable>()
  @State var currentMapView: AnyView? // <-- correct?

  func choiceView() -> some View {
    switch mapViewEnvironment.currentMapCompany {
    case "apple":
      currentMapView = AnyView(AppleMapView()) // Modifying state during view update, this will cause undefined behavior.

    default:
      currentMapView = AnyView(GoogleMapView())
    }
    return currentMapView
  }

  var body: some View {
    choiceView().onAppear {
      self.mapViewEnvironment.$value1
        .filter { $0 == "aaa" }
        .sink { _ in currentMapView.aaa() } // error
        .store(in: &self.cancellable)

      self.mapViewEnvironment.$value1
        .filter { $0 == "bbb" }
        .sink { _ in currentMapView.bbb() } // error
        .store(in: &self.cancellable)
    }
  }
}

ContentView.swift

struct ContentView: View {
  @EnvironmentObject var mapViewEnvironment: MapViewEnvironment

  var body: some View {
    VStack{
      Button(action: { self.mapViewEnvironment.value1 = "aaa" }) { Text("set aaa") }
      Button(action: { self.mapViewEnvironment.value1 = "bbb" }) { Text("set bbb") }

      CommonMapView()
    }
  }
}

1 个答案:

答案 0 :(得分:0)

自我答案。

我找到了另一种方法并更改了某些类。

ContentView.swift

struct ContentView: View {
  @EnvironmentObject var mapViewEnvironment: MapViewEnvironment

  var body: some View {
    VStack {
      Button(action: { self.mapViewEnvironment.value1 = "aaa" }) { Text("set aaa") }
      Button(action: { self.mapViewEnvironment.value1 = "bbb" }) { Text("set bbb") }
      Button(action: { self.mapViewEnvironment.currentMapCompany = "apple" }) { Text("set apple") }
      Button(action: { self.mapViewEnvironment.currentMapCompany = "google" }) { Text("set google") }

      CommonMapView()
    }
  }
}

CommonMapView.swift

struct CommonMapView: View {
  @EnvironmentObject var mapViewEnvironment: MapViewEnvironment

  var body: some View {
    ZStack {
      if mapViewEnvironment.currentMapCompany == "apple" {
        AppleMapView()
      } else {
        GoogleMapView()
      }
    }
  }
}

AppleMapView.swift

struct AppleMapView: UIViewRepresentable {
  @EnvironmentObject var mapViewEnvironment: MapViewEnvironment

  func makeUIView(context: Context) -> MKMapView {
    let view = MKMapView()
    view.mapType = .standard

    willAppear(context)

    return view
  }

  ...

  func makeCoordinator() -> AppleMapView.Coordinator {
    return Coordinator()
  }

  static func dismantleUIView(_ uiView: MKMapView, coordinator: AppleMapView.Coordinator) {
    coordinator.cancellable.removeAll()
  }

  final class Coordinator {
    var cancellable = Set<AnyCancellable>()
  }
}

extension AppleMapView: MapViewProtocol {
  func willAppear(_ context: Context) {
    mapViewEnvironment.$value1.filter { $0 == "aaa" }.sink { _ in self.aaa() }.store(in: &context.coordinator.cancellable)
    mapViewEnvironment.$value1.filter { $0 == "bbb" }.sink { _ in self.bbb() }.store(in: &context.coordinator.cancellable)
  }

  func aaa() { print("AppleMapView - aaa") }

  func bbb() { print("AppleMapView - bbb") }
}