消除模态并返回containerView中显示的childViewController [英] dimiss modal and return to presented childViewController in containerView
问题描述
我在关闭容器视图中从childviewController呈现的模式视图时遇到了一些问题.我有一个UINavigationController作为rootViewController(MainNavigationController),并显示了来自selectedSegmentIndex 1(secondViewController)的childViewControllers之一的模式.模态很好呈现,但是当我关闭模态返回第二视图控制器(HomeController的子类)时,它使我回到selectedIndex 0,而不是从中呈现出selectedIndex 1 childViewController.我希望模态关闭,然后将用户返回到从(secondViewController)呈现的childViewController,而不返回到selectedIndex0.预先感谢!
I am having a bit of an issue with dismissing a modal view presented from a childviewController in a container view. I have a UINavigationController as the rootViewController (MainNavigationController), and present a modal from one of the childViewControllers from the selectedSegmentIndex 1 (secondViewController). The modal is presented fine, but when I dismiss the modal to go back to the secondViewController(a subclass of HomeController) it returns me back to selectedIndex 0, so not the selectedIndex 1 childViewController it was presented from. I would like the modal to dismiss and return the user back to childViewController it was presented from (the secondViewController) and not return back to selectedIndex 0. Thanks in advance!
//NavigationConroller作为rootViewController
// NavigationConroller as rootViewController
class MainNavigationController: UINavigationController {
var segmentedController: UISegmentedControl!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let vc1 = TravelersFeedVC()
let vc2 = ProfileVC()
if isLoggedIn() {
// assume user is logged in
let homeController = HomeController()
viewControllers = [homeController]
homeController.firstViewController = vc1
homeController.secondViewController = vc2
} else {
perform(#selector(showLoginController), with: nil, afterDelay: 0.01)
}
}
fileprivate func isLoggedIn() -> Bool {
return UserDefaults.standard.isLoggedIn()
}
func showLoginController() {
let loginController = LoginController()
present(loginController, animated: true, completion: {
// perhaps do something here later
})
}
}
//HomeController作为parentViewController
// HomeController as parentViewController
class HomeController: UIViewController, FBSDKLoginButtonDelegate {
// child view controllers to put inside content view
var firstViewController: TravelersFeedVC?
var secondViewController: ProfileVC?
private var activeViewController: UIViewController? {
didSet {
removeInactiveViewController(inactiveViewController: oldValue)
updateActiveViewController()
}
}
private func removeInactiveViewController(inactiveViewController: UIViewController?) {
if let inActiveVC = inactiveViewController {
// call before removing child view controller's view from hierarchy
inActiveVC.willMove(toParentViewController: nil)
inActiveVC.view.removeFromSuperview()
// call after removing child view controller's view from hierarchy
inActiveVC.removeFromParentViewController()
}
}
private func updateActiveViewController() {
if let activeVC = activeViewController {
// call before adding child view controller's view as subview
addChildViewController(activeVC)
activeVC.view.frame = contentView.bounds
contentView.addSubview(activeVC.view)
// call before adding child view controller's view as subview
activeVC.didMove(toParentViewController: self)
}
}
// UI elements
lazy var contentView: UIView = {
let tv = UIView()
tv.backgroundColor = UIColor.purple
tv.translatesAutoresizingMaskIntoConstraints = false
tv.layer.masksToBounds = true
return tv
}()
var segmentedController: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
activeViewController = firstViewController
checkIfUserIsLoggedIn()
view.addSubview(contentView)
setupProfileScreen()
let items = ["Travelers", "Me"]
segmentedController = UISegmentedControl(items: items)
navigationItem.titleView = segmentedController
segmentedController.tintColor = UIColor.black
segmentedController.selectedSegmentIndex = 0
// Add function to handle Value Changed events
segmentedController.addTarget(self, action: #selector(HomeController.segmentedValueChanged(_:)), for: .valueChanged)
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(handleSignOut))
navigationItem.leftBarButtonItem?.tintColor = UIColor.black
}
// reference to collectionViewController
var travelersFeedVC: TravelersFeedVC!
func segmentedValueChanged(_ sender:UISegmentedControl!)
{
switch segmentedController.selectedSegmentIndex {
case 0:
activeViewController = firstViewController
case 1:
activeViewController = secondViewController
default: // Do nothing
break
}
}
//containerView中的secondViewcontroller,其中模态来自于
// secondViewcontroller in containerView where modal is presented from
class ProfileVC: UIViewController {
// button to present modal
lazy var placesButton: UIButton = {
let customButton = UIButton(type: .system)
customButton.backgroundColor = UIColor.clear
// customButton.frame = CGRect(x: 150, y: 50, width: 120, height: self.view.frame.height)
customButton.setTitle("## of Places", for: .normal)
customButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
customButton.setTitleColor(.white, for: .normal)
customButton.addTarget(self, action: #selector(handleShowPlacesVC), for: .touchUpInside)
return customButton
}()
// function to call to present modal
func handleShowPlacesVC() {
let placesVC = PlacesTableVC()
let navigationController = UINavigationController(rootViewController: placesVC)
present(navigationController, animated: true, completion: nil)
}
//模式视图关闭
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "back", style: .plain, target: self, action: #selector(handleCancel))
}
// dismiss modal view to return to secondViewController in childViewController containerView
func handleCancel() {
dismiss(animated: true, completion: nil)
}
推荐答案
关闭模式对话框时,将调用MainNavigationController中的viewDidAppear函数.在那里,您为其设置了一个新的homeController.这将在firstController的设置下触发HomeController中的viewDidload.尝试在此处设置断点,您会看到它.
When closing the modal dialog the viewDidAppear function in MainNavigationController is called. There you set a new homeController with it's childs. This will trigger a viewDidload in the HomeController with setting of firstViewController. Try to set a breakpoint there and you will see it.
我建议避免在viewDidAppear中创建内容,而应使用viewDidLoad.
I suggest to avoid content creation in viewDidAppear, use viewDidLoad instead.
另一个提示:关闭"定义为:关闭由视图控制器以模态形式显示的视图控制器." -例如,如果您在模式vc上方打开警报,它将关闭警报,而不是模式视图(自身).正确的实现必须在呈现控制器(打开该控制器的控制器)上调用dismiss:"presentingViewController?.dismiss()" 它可以在您的代码中使用,因为Apple在没有任何显示的情况下实现了后备功能,但这是一个陷阱,有时会引起一些头痛.
Another hint: 'dismiss' is defined as: 'Dismisses the view controller that was presented modally by the view controller.' - If you open for instance an alert above your modal vc it closes the alert, not the modal view (self). A correct implementation has to call dismiss on the presenting controller (same controller that opened it): "presentingViewController?.dismiss()" It works in your code because apple has implemented a fallback for the case that nothing is presented, but it's a trap that cause some headache sometime.
这篇关于消除模态并返回containerView中显示的childViewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!