swift - 根据最近关于用于在 VC 之间传递数据的闭包的问题,在 rootVC 中使用 containerVC 时我将如何做同样的事情?
问题描述
我看到了一个最近的赏金问题(如果你想看的话,可以找到链接)关于使用闭包在 VC 之间传递数据,其中一个 VC 嵌入在导航控制器中。虽然使用闭包相当容易,因为两个 VC 之间有一个直接的接触点(以 segue 的形式),但我一直想知道如果不是这种情况,它会如何工作。
例如,考虑以下设置(类似于启发本文的 OG 问题):
RootVC,它有一个计数器 UILabel
一个 subContainer VC,它占据 RootVC 的下半部分,它有一个按钮,按下它应该将 RootVC 上的 UILabel 增加一。
我准备了如下代码(其中一些代码取自 OG 问题):
根VC:
class RootVC: UIViewController {
var tappedCount: Int = 0
let pagingContainer: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var label: UILabel = {
let label = UILabel()
label.text = "\(tappedCount)"
label.textAlignment = .center
label.font = UIFont(name: "Copperplate", size: 90)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(label)
view.addSubview(pagingContainer)
pagingContainer.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
pagingContainer.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1).isActive = true
pagingContainer.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
pagingContainer.heightAnchor.constraint(equalToConstant: 500).isActive = true
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
addChild(pageController)
pageController.didMove(toParent: self)
pageController.view.translatesAutoresizingMaskIntoConstraints = false
pagingContainer.addSubview(pageController.view)
pageController.view.heightAnchor.constraint(equalTo: pagingContainer.heightAnchor, multiplier: 1).isActive = true
pageController.view.widthAnchor.constraint(equalTo: pagingContainer.widthAnchor, multiplier: 1).isActive = true
pageController.view.topAnchor.constraint(equalTo: pagingContainer.topAnchor).isActive = true
pageController.view.bottomAnchor.constraint(equalTo: pagingContainer.bottomAnchor).isActive = true
pageController.view.leadingAnchor.constraint(equalTo: pagingContainer.leadingAnchor).isActive = true
pageController.view.trailingAnchor.constraint(equalTo: pagingContainer.trailingAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: pagingContainer.topAnchor).isActive = true
}
}
子容器VC:
class SubContainerVC: UIViewController {
var callback : (() -> Void)?
let button: UIButton = {
let button = UIButton()
button.setTitle("Button!", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
button.backgroundColor = .green
return button
}()
@objc func buttonPressed(_ sender: UIButton) {
print("Hello")
//Pressing this button should increment the label on RootVC by one.
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBlue
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
和 PageViewController 快速文件:
class PageViewController: UIPageViewController {
lazy var subViewControllers:[UIViewController] = {
return [SubContainerVC()]
}()
init(transitionStyle style:
UIPageViewController.TransitionStyle, navigationOrientation: UIPageViewController.NavigationOrientation, options: [String : Any]? = nil) {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
setViewControllerFromIndex(index: 0)
}
func setViewControllerFromIndex(index:Int) {
self.setViewControllers([subViewControllers[index]], direction: UIPageViewController.NavigationDirection.forward, animated: true, completion: nil)
}
}
extension PageViewController: UIPageViewControllerDelegate, UIPageViewControllerDataSource {
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return subViewControllers.count
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex:Int = subViewControllers.firstIndex(of: viewController) ?? 0
if currentIndex <= 0 {
return nil
}
return subViewControllers[currentIndex-1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex:Int = subViewControllers.firstIndex(of: viewController) ?? 0
if currentIndex >= subViewControllers.count-1 {
return nil
}
return subViewControllers[currentIndex+1]
}
}
解决方案
您可以将闭包下游注入到SubContainerVC
,这将导致闭包执行出现在上游。
类似的东西(只保留相关的 VC 代码):
class SubContainerVC {
var buttonCallback: () -> Void = { }
@objc func buttonPressed(_ sender: UIButton) {
print("Hello")
buttonCallback()
}
}
class PageViewController: UIViewController {
// Note that you don't need the extra closure call for lazy vars
lazy var subViewControllers = [SubContainerVC()] {
didSet {
// just in case the controllers might change later on
subViewControllers.forEach { $0.buttonCallback = buttonCallback }
}
}
var buttonCallback: () -> Void = { } {
didSet {
subViewControllers.forEach { $0.buttonCallback = buttonCallback }
}
}
}
class RootVC: UIViewController {
var tappedCount: Int = 0 {
didSet {
label.text = "\(tappedCount)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
// this will trigger the `didSet` from PageViewController, resulting
// in the callback being propagated downstream
pageController.buttonCallback = { self.tappedCount += 1 }
}
}
推荐阅读
- sql-server - 重新登录无法通过 t-sql xp_commandshell 工作,但相同的命令在命令提示符下工作
- eclipse - Create new instance of a project in intellij
- javascript - TypeError: _fieldRef$current.blur 不是函数
- firebase - Flutter/Firebase - type 'Future
' is not a subtype of type 'int' - c - Generate integer random number using available binaryrandom (which return 0 or 1) function
- python - How to resolve graph2vec error invalid literal for int()?
- android - 使用 ViewModel 未在 Webview 中加载 URL
- python - While trying to display wav file using scipi im getting the following error "ushort format requires 0 <= number <= 0xffff"
- python-3.x - 使用 PyInstaller 缺少按钮图标
- java - how can I get the only entered values from an array?