如何在 SwiftUI 中的 PageViewController 中传递一些视图?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中的 PageViewController 中传递一些视图?【英文标题】:How to pass some views in PageViewController in SwiftUI? 【发布时间】:2020-05-04 10:19:08 【问题描述】:

在我的 SwiftUI 应用程序中,当我尝试在 PageViewController 中传递一些视图时出现错误。我不明白他们想要什么意思。我用经典的方式设置了这样的 PageViewController:

PageViewController 文件:

import Foundation
import UIKit
import SwiftUI

struct PageViewController: UIViewControllerRepresentable 

  @Binding var currentPageIndex: Int
  @EnvironmentObject var viewData: ViewData

  var viewControllers: [UIViewController]

  func makeCoordinator() -> Coordinator 
    Coordinator(self)
  

  func makeUIViewController(context: Context) -> UIPageViewController 

    let pageViewController = UIPageViewController(
      transitionStyle: .scroll,
      navigationOrientation: .horizontal,
      options: [UIPageViewController.OptionsKey.interPageSpacing : self.viewData.pageViewControllerPadding]
    )

    pageViewController.dataSource = context.coordinator
    pageViewController.delegate = context.coordinator

    let compassScreen = viewControllers[0]
    let sonarScreen = viewControllers[1]

    compassScreen.view.backgroundColor = UIColor.clear
    sonarScreen.view.backgroundColor = UIColor.clear

    return pageViewController
  

  func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) 
    pageViewController.setViewControllers(
      [viewControllers[currentPageIndex]], direction: currentPageIndex == 0 ? .reverse : .forward, animated: true
    )
  

  class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate 

    var parent: PageViewController

    init(_ pageViewController: PageViewController) 
      self.parent = pageViewController
    

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 
      // Retrieves the index of the currently displayed view controller
      guard let index = parent.viewControllers.firstIndex(of: viewController) else 
        return nil
      

      // Shows the last view controller when the user swipes back from the first view controller
      if index == 0 
        return nil
      

      // Show the view controller before the currently displayed view controller
      return parent.viewControllers[index - 1]
    

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 
      // Retrieves the index of the currently displayed view controller
      guard let index = parent.viewControllers.firstIndex(of: viewController) else 
        return nil
      

      // Shows the first view controller when the user swipes further from the last view controller
      if index + 1 == parent.viewControllers.count 
        return nil
      

      // Show the view controller after the currently displayed view controller
      return parent.viewControllers[index + 1]
    

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
      if completed, let visibleViewController = pageViewController.viewControllers?.first, let index = parent.viewControllers.firstIndex(of: visibleViewController) 
        parent.currentPageIndex = index
      
    
  

PageView 文件:

import SwiftUI

struct PageView<Page: View>: View 

  @State var currentPage = 0

  var viewControllers: [UIHostingController<Page>]

  init(_ views: [Page]) 
    self.viewControllers = views.map UIHostingController(rootView: $0) 
  

  var body: some View 
    VStack(alignment: .center) 
      PageViewController(
        currentPageIndex: $currentPage,
        viewControllers: viewControllers
      )
    
  

还有我的 contentView 文件,我尝试像这样传递我的观点:

import SwiftUI
import CoreLocation

@EnvironmentObject var settingsStore: SettingsStore
@EnvironmentObject var userData: UserData    

struct ContentView: View     
  var body: some View 
    VStack() 
      PageView([
        Compass()
         .padding(.bottom, 10)
         .environmentObject(settingsStore)
         .environmentObject(userData)
        Sonar()
          .padding(.bottom, 10)
          .environmentObject(settingsStore)
          .environmentObject(userData)
      ])
    
  

PageView(...) 行出现此错误:

我试着把这个:

 PageView([
   UIHostingController(rootView: Compass()
     .padding(.bottom, 10)
     .environmentObject(settingsStore)
     .environmentObject(userData)
   ),
   UIHostingController(rootView: Sonar()
     .padding(.bottom, 10)
     .environmentObject(settingsStore)
     .environmentObject(userData)
   )
 ])

但是我又报错了:

我不知道该怎么办?

【问题讨论】:

【参考方案1】:

问题在于,当您应用修饰符时,生成的视图不再是 Compass(或 Page)类型,而是变成“某些视图”,请看:https://developer.apple.com/documentation/swiftui/view/padding(_:_:)

因此,您不能创建这样的数组。相反,您应该将您的数组元素类型擦除到 AnyView(AnyView(Compass().padding())),并将您的数组元素类型修改为 UIHostingController&lt;AnyView&gt;

【讨论】:

以上是关于如何在 SwiftUI 中的 PageViewController 中传递一些视图?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 macOS 上检测 SwiftUI 中的键盘事件?

如何知道 UIKit 视图控制器中的 swiftUI 事件? ||如何提供 swiftUI 和 uikit 之间的通信

如何在 SwiftUI 中的 PageViewController 中传递一些视图?

如何在 SwiftUI 中的列表下方添加一个按钮? [关闭]

如何有效地过滤 SwiftUI 中的长列表?

如何在swiftui中的视图之间传递变量?