在我的TabBarViewController中,我正在创建一个导航并以模态方式呈现它。
func viewDidLoad(){
super.viewDidLoad();
//Create a present this view controller in viewDidLoad
self.navController = UINavigationController()
self.presentViewController(self.navController, animated: true, completion: nil)
}
//This method gets called when TabBarVC gets a NSNotification
func showMessageForUser(user_id: Int){
let mvc = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
mvc.user_id = user_id //set this user
//display this to the user.
self.navController.pushViewController(mvc, animated: true)
}
这很简单。但是,我想这样做:
重新排序后,所有“后退”按钮应按预期工作。
答案 0 :(得分:4)
您可以使用setViewControllers(_:animated:)
重新排列视图控制器堆栈。您无需执行任何特殊操作即可使后退按钮正常工作。导航控制器根据其viewControllers
数组中的第二项设置后退按钮(如果有第二项),并在更新viewControllers
数组时更新后退按钮。
以下是我如何做到这一点。首先,我们向UIViewController
添加一个方法,询问它是否是特定userId
的视图控制器。由于大多数视图控制器不是(也可能不是)正确的视图控制器,它只返回false
:
extension UIViewController {
func isViewControllerForUserId(userId: Int) -> Bool {
return false
}
}
然后我们在MessagesViewController
中覆盖此方法,以便在适当时返回true
:
extension MessagesViewController {
override func isViewControllerForUserId(userId: Int) -> Bool {
return self.userId == userId
}
}
现在,为了显示特定用户的视图控制器,我们在导航控制器的堆栈中搜索现有的视图控制器。我们采取的行动取决于我们是否找到了它:
func showMessageForUserId(userId: Int) {
if let index = navController.viewControllers.indexOf({ $0.isViewControllerForUserId(userId) }) {
navController.moveToTopOfNavigationStack(viewControllerAtIndex: index)
} else {
pushNewViewControllerForUserId(userId)
}
}
如果我们没有找到它,我们会创建一个新的视图控制器并推送它:
private func pushNewViewControllerForUserId(userId: Int) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
vc.userId = userId
self.navController.pushViewController(vc, animated: true)
}
如果我们确实找到了它,我们会使用以下方法将其移动到导航堆栈的顶部:
extension UINavigationController {
func moveToTopOfNavigationStack(viewControllerAtIndex index: Int) {
var stack = viewControllers
if index == stack.count - 1 {
// nothing to do because it's already on top
return
}
let vc = stack.removeAtIndex(index)
if (reorderingIsBuggy) {
setViewControllers(stack, animated: false)
}
stack.append(vc)
setViewControllers(stack, animated: true)
}
private var reorderingIsBuggy: Bool {
// As of iOS 9.3 beta 3, `UINavigationController` drops the prior top-of-stack
// when you use `setViewControllers(_:animated:)` to move a lower item to the
// top with animation. The workaround is to remove the lower item from the stack
// without animation, then add it to the top of the stack with animation. This
// makes it display a push animation instead of a pop animation and avoids
// dropping the prior top-of-stack.
return true
}
}
答案 1 :(得分:0)
这是方法showMessageForUser(_ :),用你的方法替换你的,就像魅力一样......
func showMessageForUser(user_id: Int){
var mvcItem: MessagesViewController?
var controllers: [UIViewController] = (self.navController?.viewControllers)!
var matchindex: Int? = -1
for (index, viewItem) in controllers.enumerate() {
if (viewItem is MessagesViewController) {
if viewItem.user_id == user_id {
matchindex = index
break
}
}
}
if matchindex != -1 { //jus making sure a matching index was found
mvcItem = (controllers.removeAtIndex(matchindex!)) as? MessagesViewController
}
if mvcItem != nil {
self.navController?.viewControllers = controllers
self.navController?.pushViewController(mvcItem!, animated: true)
} else {
let mvc = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
mvc.user_id = user_id //set this user
//display this to the user.
self.navController.pushViewController(mvc, animated: true)
}
}
答案 2 :(得分:0)
只是为了让代码更易于推理我将创建自己的UINavigationController。
这样的事情:
final class MessagesNavigationController: UINavigationController {
// Option 1: If you want to dismiss everything that was in the midle, you can just do this:
func showMessageForUser(user_id: Int){
guard let messagesViewController = findMessagesViewController(withUserId: user_id) else {
let mvc = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
mvc.user_id = user_id
pushViewController(mvc, animated: true)
return
}
popToViewController(messagesViewController, animated: false)
}
private func findMessagesViewController(withUserId userId: Int) -> MessagesViewController? {
for viewController in viewControllers {
guard let messagesViewController = viewController as? MessagesViewController
where messagesViewController.user_id == userId else { continue }
return messagesViewController
}
return nil
}
// Option 2: If you want to move the viewcontroller from the position it currently is, to the end
// but keeping everything in the middle, you can do this:
func showMessageForUser2(user_id: Int){
guard let index = findMessagesViewControllerIndex(withUserId: user_id) else {
let mvc = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
mvc.user_id = user_id
pushViewController(mvc, animated: true)
return
}
// This is the main change
let viewController = viewControllers.removeAtIndex(index)
pushViewController(viewController, animated: false)
}
private func findMessagesViewControllerIndex(withUserId userId: Int) -> Int? {
for (index, viewController) in viewControllers.enumerate() {
guard let messagesViewController = viewController as? MessagesViewController
where messagesViewController.user_id == userId else { continue }
return index
}
return nil
}
}
所以你的TabBarController看起来像这样:
var navController: MessagesNavigationController!
override func viewDidLoad(){
super.viewDidLoad();
navController = MessagesNavigationController()
presentViewController(self.navController, animated: true, completion: nil)
}
func showMessageForUser(user_id: Int){
navController.showMessageForUser(user_id)
}