0

我在关闭容器视图中的 childviewController 呈现的模态视图时遇到了一些问题。我有一个 UINavigationController 作为 rootViewController (MainNavigationController),并从 selectedSegmentIndex 1 (secondViewController) 中的一个 childViewControllers 中呈现一个模式。模态显示得很好,但是当我关闭模态返回到 secondViewController(HomeController 的子类)时,它会将我返回到 selectedIndex 0,而不是从中呈现的 selectedIndex 1 childViewController。我希望模态关闭并将用户返回到从(第二个视图控制器)呈现的 childViewController,而不是返回到 selectedIndex 0。提前致谢!

// NavigationConroller 作为 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

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 模态显示的地方

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)
    }
4

2 回答 2

0

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.

I suggest to avoid content creation in viewDidAppear, use viewDidLoad instead.

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.

于 2017-04-16T18:23:38.030 回答
0

很有可能虽然您是present从子视图控制器调用的,但它实际上并没有处理演示文稿。来自苹果文档

您调用此方法的对象可能并不总是处理演示文稿的对象。每种演示风格都有不同的规则来管理其行为。例如,全屏演示必须由本身覆盖整个屏幕的视图控制器进行。如果当前视图控制器无法满足请求,它会将请求沿视图控制器层次结构向上转发到其最近的父级,然后父级可以处理或转发该请求。

由于您保留了活动视图控制器的引用,因此一种解决方案可能是在解雇时显式设置索引。

于 2017-04-16T18:28:46.543 回答