按下后退按钮时如何跳过上一个视图
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>NavigationController
。 Navigation Controller
是 initial 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)
之后,当您按下返回时,您将被导航到您想要的控制器,而不会看到您已删除的先前视图控制器的弹出动画。
【讨论】:
以上是关于按下后退按钮时如何跳过上一个视图的主要内容,如果未能解决你的问题,请参考以下文章