按下后退按钮时如何跳过上一个视图

Posted

技术标签:

【中文标题】按下后退按钮时如何跳过上一个视图【英文标题】:How to Skip Over Previous View When Back Button Pressed 【发布时间】:2016-10-04 19:40:12 【问题描述】:

我的导航是:

List of Friends with messages Controller(点击撰写)-> List of friends to select chatting(选择好友)-> Show chat with friend

目前,如果在Show chat with friend 内,并且用户选择了back,它会将他们带到List of friends to select chatting 控制器。 我希望跳过这个控制器,然后在返回选择时导航到List of Friends with messages Controller

注意:List of Friends with messages Controller 是嵌入在选项卡中的。

我曾尝试在List of friends to select chatting 之间的segue 内使用:self.navigationController?.viewControllers.removeLast() 将其从堆栈中删除。但是在导航到Show chat with friend 之后,后退按钮消失了……

如何允许我描述的导航?

【问题讨论】:

您的想法是正确的,但我建议您修改 viewWillAppear 中的 self.navigationController?.viewControllers 数组,以运行您的 show chat with friend 视图控制器。请注意,在这种情况下,您不能只使用 removeLast。您将不得不删除元素 count-2 使用委托、通知来执行此操作。 相信***.com/questions/18824186/…这里的答案会对你有所帮助。 @axel 哪里有快速翻译? 提供的答案中有 【参考方案1】:

如果您的目标是跳过第二个UIViewController 并从第三个UIViewController 跳回第一个UIViewController。试试下面的代码:

// This count will return how many view controllers are there in navigation stack
let controllersInNavigationCount = self.navigationController?.viewControllers.count

// This will pop to first UIViewController skipping second UIViewController
self.navigationController?.popToViewController(self.navigationController?.viewControllers[controllersInNavigationCount!-2] as! FirstViewController, animated: true)

【讨论】:

【参考方案2】:

这有点棘手。我将如何解决这个问题是

在 viewWillAppear 下的 Show chat withfriend View Controller 中,我将设置一个名为 pageViewed 的 NSUserDefault 并将其值设置为 1。

现在在朋友列表中选择 viewWillAppear 下的聊天视图控制器我会检查 pageViewed NSUserDefault 的值是否为 1。如果将其设置回 0 并调用 make a 将其从堆栈中删除.

//Remove from Nav-Stack
[self.navigationController popViewControllerAnimated:YES];

同样,它有点棘手,但绝对可行。

【讨论】:

使用 unwindForSegue(unwindSegue: UIStoryboardSegue, 朝向ViewController: UIViewController) @jjtalie,展开转场有更好的效果:您不会在通往目标控制器的途中通过中间控制器进行动画处理,但据我所知,您无法连接将 segue(或任何其他操作)展开到导航栏的后退按钮。如果 op 愿意用自定义按钮替换后退按钮,或者在第三个控制器的界面中添加一个额外的按钮,那么 unwind segue 似乎是一个很好、简单的解决方案。【参考方案3】:

Xcode 7.2.1 ios 9.2 斯威夫特 2.1.1 OSX 10.10.5

以下内容对我有用:

    您可以在循环中使用navigationController?.popViewControllerAnimated(true) 来跳过任意数量的视图控制器。

    如果要返回的 ViewController 是 UINavigationController 堆栈中的第一个 ViewController,则可以使用navigationController?.popToRootViewControllerAnimated(true) 返回第一个视图控制器。

应用仍然通过跳过的 ViewController 进行动画处理,因此您会看到跳过的 View 在到达目标 ViewController 的途中滑过。

我尝试过使用: self.navigationController?.viewControllers.removeLast(),在 在朋友列表之间切换以选择聊天以将其删除 从堆栈中。但是在导航到 Show chat with 之后 朋友,后退按钮消失了……

嗯......这似乎应该工作。后退按钮信息是从前一个 ViewController 的navigationItem 属性中检索的。前一个 ViewController 的 navigationItem.backBarButtonItem 包含您看到的后退按钮的信息。那么,当您从堆栈中删除该 ViewController 时,为什么 UINavigationController 没有从早期的 ViewController 中检索到 navigationItem.backBarButtonItem 信息?

听起来目标 ViewController 可能已经获得了对前一个 ViewController 的弱引用——你从堆栈中删除的那个。然后,当您从 viewControllers 数组中删除前一个 ViewController 时,前一个 ViewController 消失了,并且弱引用被分配为 nil——这阻止了目标 ViewController 获取返回按钮的信息;因此没有显示返回按钮。

AppDelegate.swift

//
//  AppDelegate.swift
//  NavigationBarExample
//
//  Copyright © 2016 7stud. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
        // Override point for customization after application launch.

        let navController = window!.rootViewController as! UINavigationController
        let friendsController = navController.topViewController as! FriendsTableViewController
        friendsController.friendStore = FriendStore(names: ["Joe", "Cathy", "Bobo"])

        return true
    

...
...

FriendsTableViewController.swift

//  FriendsTableViewController.swift
//  NavigationBarExample
//
//
//  Copyright © 2016 7stud. All rights reserved.
//

import UIKit

class FriendsTableViewController: UITableViewController 
    var friendStore: FriendStore!

    override func viewDidLoad() 
        super.viewDidLoad()

        //Prevent TableView from underlapping the status bar:
        let statusBarHeight = UIApplication.sharedApplication().statusBarFrame.height
        let insets = UIEdgeInsets(
            top: statusBarHeight, left: 0, bottom: 0, right: 0
        )
        tableView.contentInset = insets
        tableView.scrollIndicatorInsets = insets
    

    //MARK: - UITableViewDataSource methods:

    override func tableView(tableView: UITableView,
        numberOfRowsInSection section: Int)
        -> Int
    
        return friendStore.allFriends.count
    

    override func tableView(tableView: UITableView,
        cellForRowAtIndexPath
        indexPath: NSIndexPath)
        -> UITableViewCell
    
        let friend = friendStore.allFriends[indexPath.row]

        let cell = tableView.dequeueReusableCellWithIdentifier(
            "UITableViewCell-Default",
            forIndexPath: indexPath
        )
        cell.textLabel?.text = friend.name

        return cell
    

    //MARK: - Segue:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

        if segue.identifier == "ShowFriend" 
            if let row = tableView.indexPathForSelectedRow?.row 
                let viewController2 = segue.destinationViewController as! ViewController2
                viewController2.friend = friendStore.allFriends[row]
                viewController2.previousTitle = navigationItem.title
            


        
    


FriendStore.swift

//
//  FriendStore.swift
//  NavigationBarExample
//
//  Copyright © 2016 7stud. All rights reserved.
//

import Foundation

class FriendStore 

    var allFriends: [Friend] = []

    init(names: [String]) 
        for name in names 
            allFriends.append(Friend(name: name) )
        
    

Friend.swift

//
//  Friend.swift
//  NavigationBarExample
//
//  Copyright © 2016 7stud. All rights reserved.
//

import Foundation

class Friend: NSObject 
    var name: String

    init(name: String) 
        self.name = name

        super.init()
    


ViewController2.swift

//
//  ViewController2.swift
//  NavigationBarExample
//
//  Copyright © 2016 7stud. All rights reserved.
//

import UIKit

class ViewController2: UIViewController 
    var friend: Friend! 
        didSet 
            navigationItem.title = friend.name
        
    

    var previousTitle: String!

    override func viewDidLoad() 
        //Set the correct title for the back button on the next view controller:
        let myBackButtonItem = UIBarButtonItem(
            title: previousTitle,
            style: .Plain,
            target: nil,
            action: nil  //An action specified here won't get called--I
                         //think the NavigationController must overwrite this sometime later.
        )

        navigationItem.backBarButtonItem = myBackButtonItem

    

ViewController3.swift

//
//  ViewController3.swift
//  NavigationBarExample
//
//  Copyright © 2016 7stud. All rights reserved.
//

import UIKit

class ViewController3: UIViewController 

    override func viewWillDisappear(animated: Bool) 
        super.viewWillDisappear(animated)

        let goBackCount = 2

        if let navController = navigationController 
            let viewControllers = navController.viewControllers

            if viewControllers.count >= goBackCount 
                for _ in 1...goBackCount 
                    navController.popViewControllerAnimated(true)
                

            
        
    

完成同样事情的一种不太通用的方法是:如果您要返回的控制器是根 ViewController,即它是 UINavigationController 堆栈中的第一个控制器,那么在 viewWillDisappear() 中,您可以简单地调用 navigationController?.popToRootViewControllerAnimated(true)

Main.storyboard: 在情节提要中创建Table View 后,我选择了Table View,在Xcode 菜单栏中,我选择了Editor>Embed In>NavigationControllerNavigation Controllerinitial view controller。我还双击导航栏中间的Table View,并将标题设置为Friends

然后我控制+从Table View中的Prototype Cell拖动到View Controller2;从弹出窗口中我选择了Selection Segue->Show

然后我控制+从View Controller2中的按钮拖动到View Controller3;从弹出窗口中我选择了Action Segue->Show

【讨论】:

【参考方案4】:

返回 N 个视图控制器的最佳方法是使用 navigationController.viewControllers。当您到达最后一个 viewController 时,您会像这样删除 N 个之前的 viewController:

let previousViewControllerIndex = navigationController.viewControllers.count - N navigationController.viewControllers.remove(at: previousViewControllerIndex)

之后,当您按下返回时,您将被导航到您想要的控制器,而不会看到您已删除的先前视图控制器的弹出动画。

【讨论】:

以上是关于按下后退按钮时如何跳过上一个视图的主要内容,如果未能解决你的问题,请参考以下文章

在android中按下后退按钮后如何返回相同的选项卡?

在iOS中按下后退按钮时如何创建确认弹出窗口?

如何检测在导航控制器的下一个视图控制器中按下后退按钮

当我按下后退按钮 Swift 3 时,删除的数据重新出现

按下后退按钮后,从另一个视图控制器更改按钮

如果用户按下后退按钮,如何调用一些代码