我们应该为以下功能使用 UIView 还是 UIViewController?
Should we be using UIView or UIViewController for the following feature?
我们有以下应用程序,用户可以从侧面菜单切换到不同的“页面”(紫色、黄色……颜色)。
我在想,“页面”应该实现为UIView
,还是应该实现为UIViewController
?
页面应负责
- 读取/写入 CoreData。
- 可能持有
UIPageView
,用户可以滑动浏览多个 child 页面,如 https://i.stack.imgur.com/v0oNo.gif 所示
- 持有
UICollectionView
.
- 用户可以拖动和移动
UICollectionView
中的项目
- 用户可以对
UICollectionView
中的项目执行各种上下文操作(删除、克隆...)。
- 将来可以轻松移植到 iPad。
目前,我使用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
的功能,例如
viewDidLoad
回调。
viewWillLoad
回调。
viewDidLayoutSubviews
回调。
- ...
但是,我不清楚失去这些功能是否会阻止我实现适当的“页面”?
我可以知道,我应该使用 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)
}
}
我们有以下应用程序,用户可以从侧面菜单切换到不同的“页面”(紫色、黄色……颜色)。
我在想,“页面”应该实现为UIView
,还是应该实现为UIViewController
?
页面应负责
- 读取/写入 CoreData。
- 可能持有
UIPageView
,用户可以滑动浏览多个 child 页面,如 https://i.stack.imgur.com/v0oNo.gif 所示
- 持有
UICollectionView
. - 用户可以拖动和移动
UICollectionView
中的项目
- 用户可以对
UICollectionView
中的项目执行各种上下文操作(删除、克隆...)。 - 将来可以轻松移植到 iPad。
目前,我使用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
的功能,例如
viewDidLoad
回调。viewWillLoad
回调。viewDidLayoutSubviews
回调。- ...
但是,我不清楚失去这些功能是否会阻止我实现适当的“页面”?
我可以知道,我应该使用 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)
}
}