我们应该为以下功能使用 UIView 还是 UIViewController?

Should we be using UIView or UIViewController for the following feature?

我们有以下应用程序,用户可以从侧面菜单切换到不同的“页面”(紫色、黄色……颜色)。

我在想,“页面”应该实现为UIView,还是应该实现为UIViewController

页面应负责

目前,我使用UIView的实现如下。

private func archive() {
    if let trashView = self.trashView {
        trashView.removeFromSuperview()
        self.trashView = nil
    }
    
    if self.archiveView != nil {
        return
    }
    
    let archiveView = ArchiveView.instanceFromNib()
    
    self.view.addSubview(archiveView)
    archiveView.translatesAutoresizingMaskIntoConstraints = false
    archiveView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
    archiveView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
    archiveView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    archiveView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    
    self.archiveView = archiveView
}

private func trash() {
    if let archiveView = self.archiveView {
        archiveView.removeFromSuperview()
        self.archiveView = nil
    }
    
    if self.trashView != nil {
        return
    }
    
    let trashView = TrashView.instanceFromNib()
    
    self.view.addSubview(trashView)
    trashView.translatesAutoresizingMaskIntoConstraints = false
    trashView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
    trashView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
    trashView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    trashView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    
    self.trashView = trashView
}

我注意到如果我使用 UIView 实现“页面”,我将失去一些 UIViewController 的功能,例如

但是,我不清楚失去这些功能是否会阻止我实现适当的“页面”?

我可以知道,我应该使用 UIView 还是使用 UIViewController 来实现这些“页面”?

也许我完全误解了你的问题,但你的 UIView 应该只包含与视图本身如何向用户显示相关的逻辑。 UIView 不应包含与其他视图或模型相关的任何逻辑。

UIKit 假定您使用 MVC 模型在 Apple 平台上实现应用程序。这意味着任何与控制必须显示哪个视图以及视图应从模型获取哪些数据相关的代码都应写入 ViewController.

在 Xcode 中,您同时拥有 UICollectionViewController 和 UIPageViewController 来实现页面滑动和拖放视图。

视图控制器可以将控制权交给其他视图控制器来呈现视图。视图控制器还确定应由视图呈现的数据。请查看 this article 有关 MVC 模型的信息。

亲切的问候, MacUserT

我会用 UIViewController 这样做,因为你已经在问题中列出了所有 UIKit 回调原因。

我假设您有一个 UINavigationController 实例,该实例已为您的应用设置为 window.rootViewController。您有一个对此实例的引用,您可以使用它轻松地在不同屏幕之间切换。

例子

class SlideMenuViewController: UIViewController {
    enum Option {
        case archive
        case trash
    }
    
    var onSelect: ((_ option: Option) -> Void)?
}

class ArchiveViewController: UIViewController {}
class TrashViewController: UIViewController {}

class AppNavigator {
    
    let mainNavigationController: UINavigationController
    init(navigationController: UINavigationController) {
        self.mainNavigationController = navigationController
    }
    
    private lazy var slideMenuVC: SlideMenuViewController = {
        let slideMenu = SlideMenuViewController()
        slideMenu.onSelect = { [weak self] (option) in
            self?.openScreen(for: option)
        }
        return slideMenu
    }()
    
    private lazy var archiveVC: ArchiveViewController = {
        return ArchiveViewController()
    }()
    
    private lazy var trashVC: TrashViewController = {
        return TrashViewController()
    }()
    
    func openScreen(for option: SlideMenuViewController.Option) {
        let targetVC: UIViewController
        switch option {
        case .archive: targetVC = archiveVC
        case .trash: targetVC = trashVC
        }
        mainNavigationController.setViewControllers([targetVC], animated: true)
    }
    
}