Какой идиоматический способ управления вложенным UIView в SwiftUI - PullRequest
1 голос
/ 04 октября 2019

Я хочу показать WKWebView в иерархии представлений SwiftUI, и я хочу управлять WKWebView с помощью кнопок, реализованных в SwiftUI.

Я могу сделать это путем создания класса SwiftUI WebView, который реализует UIViewRepresentable и переносит WKWebView, вот так ...

struct WebView: UIViewRepresentable {

  func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
    return WKWebView(frame: .zero)
  }

  func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
    // Update WKWebView here if necessary
  }
}

... и затем используя его следующим образом ...


struct BrowserView: View {
  var body: some View {
    VStack {
      WebView()

      // Footer
      HStack {
        Button(action: {
          // When this is called, I want to somehow call .goBack()
          // on the WKWebView.
        }) {
          Image(systemName: "chevron.left")
        }

        ...
      } // HStack
    } // VStack
  }
}

Когда пользователь нажимает кнопку, яхочу как-то позвонить goBack на WKWebView. Как мне сделать это идиоматически в SwiftUI?

Подходы, которые я считаю, я считаю хрупкими или не идиоматичными SwiftUI ...

  • ПредставлятьСколько раз пользователь нажимал «Назад» в привязке. Попросите WebView прослушать эту привязку и вернуться назад, когда она увеличивается.

  • Попросите BrowserView создать объект, называемый чем-то вроде MutableWebViewAPI, и передать его на WebView при построении. WebView прослушивает этот объект, поэтому, когда BrowserView вызывает что-то вроде MutableWebViewAPI.goBack(), WebView делает то же самое.

1 Ответ

1 голос
/ 04 октября 2019

Я думаю, что лучший способ - это использовать возможности Combine, создав PassthroughSubject в родительском представлении, а затем подписаться на события вашего ребенка WebView.

Сначала создайте структуру в своемUIViewReprsentable, который фиксирует доступные события, которые вы хотите отправить на WebView:

struct WebView: UIViewReprsentable {

    enum WebEvent {
        case back
        case forward
    }

    let eventPublisher: AnyPublisher<WebEvent, Never>

    init(eventPublisher: AnyPublisher<WebEvent, Never>) {
        self.eventPublisher = eventPublisher

        eventPublisher.sink { event in
            // forward the appropriate event to your underlying WKWebView
        }
    }
}

Далее, в родительском элементе создайте PassthroughSubject для создания этих событий.

struct ParentView: View {
    private let eventSender = PassthroughSubject<WebView.WebEvent, Never>()

    var body: some View {
        VStack {
            Button("Back") {
                self.eventSender.send(.back)
            }
            Button("Forward") {
                self.eventSender.send(.forward)
            }

            WebView(eventPublisher: eventSender.eraseToAnyPublisher())
        }
    }
}
...