![](/img/trans.png)
[英]Remove view controller from navigation stack after push segue (using Storyboard segues)
[英]Instead of push segue how to replace view controller (or remove from navigation stack)?
我有一個小型 iPhone 應用程序,它使用導航控制器顯示 3 個視圖(此處為全屏):
首先它顯示社交網絡列表(Facebook、Google+ 等):
然后它會顯示一個 OAuth 對話框,要求提供憑據:
並且(之后,在同一個UIWebView
)獲取權限:
最后,它顯示帶有用戶詳細信息的最后一個視圖控制器(在實際應用程序中,這將是菜單,可以在其中啟動多人游戲):
這一切都很好,但我有一個問題,當用戶想要返回並選擇另一個社交網絡時:
用戶觸摸后退按鈕,而不是顯示第一個視圖,而是顯示第二個視圖,再次請求 OAuth 憑據/權限。
我能在這里做什么? Xcode 5.0.2 顯示了一個非常有限的 segues 選擇 - push 、 modal (我不能使用,因為它掩蓋了我的游戲所需的導航欄)和custom 。
我是 iOS 編程新手,但早些時候我開發了一個Adobe AIR 移動應用程序,並且可以 1) 替換視圖而不是推送和 2) 從導航堆棧中刪除不需要的視圖。
請如何在本機應用程序中執行相同操作?
為了擴展上面的各種segue,這是我的解決方案。 它具有以下優點:
轉場代碼:
- (void)perform {
// Grab Variables for readability
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
UINavigationController *navigationController = sourceViewController.navigationController;
// Get a changeable copy of the stack
NSMutableArray *controllerStack = [NSMutableArray arrayWithArray:navigationController.viewControllers];
// Replace the source controller with the destination controller, wherever the source may be
[controllerStack replaceObjectAtIndex:[controllerStack indexOfObject:sourceViewController] withObject:destinationController];
// Assign the updated stack with animation
[navigationController setViewControllers:controllerStack animated:YES];
}
您可以使用自定義轉場:為此,您需要創建一個繼承 UIStoryboardSegue 的類(例如 MyCustomSegue),然后您可以使用類似的內容覆蓋“執行”
-(void)perform {
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
UINavigationController *navigationController = sourceViewController.navigationController;
// Pop to root view controller (not animated) before pushing
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:destinationController animated:YES];
}
此時轉到Interface Builder,選擇“自定義”segue,並輸入您的類的名稱(例如MyCustomSegue)
在迅速
override func perform() {
if let navigationController = self.source.navigationController {
navigationController.setViewControllers([self.destination], animated: true)
}
}
自定義轉場對我不起作用,因為我有一個 Splash 視圖控制器,我想替換它。 由於列表中只有一個視圖控制器,因此popToRootViewController
仍將 Splash 留在堆棧中。 我使用以下代碼替換了單個控制器
-(void)perform {
UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
UIViewController *destinationController = (UIViewController*)[self destinationViewController];
UINavigationController *navigationController = sourceViewController.navigationController;
[navigationController setViewControllers:@[destinationController] animated:YES];
}
現在在 Swift 4 中:
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
source.navigationController?.setViewControllers([destination], animated: true)
}
}
現在在 Swift 2.0
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
sourceViewController.navigationController?.setViewControllers([destinationViewController], animated: true)
}
}
對於這個問題,我認為答案很簡單
然后將 ViewControllers 數組設置回導航控制器,如下所示:
if let navController = self.navigationController { let newVC = DestinationViewController(nibName: "DestinationViewController", bundle: nil) var stack = navController.viewControllers stack.remove(at: stack.count - 1) // remove current VC stack.insert(newVC, at: stack.count) // add the new one navController.setViewControllers(stack, animated: true) // boom! }
與Swift 3完美配合。
希望對一些新人有所幫助。
干杯。
ima747 的 swift 2 版本回答:
override func perform() {
let navigationController: UINavigationController = sourceViewController.navigationController!;
var controllerStack = navigationController.viewControllers;
let index = controllerStack.indexOf(sourceViewController);
controllerStack[index!] = destinationViewController
navigationController.setViewControllers(controllerStack, animated: true);
}
正如他所說,它具有以下優點:
使用 unwind segue 將是解決這個問題的最合適的方法。 我同意勞羅的觀點。
這是設置從 detailsViewController[或 viewController3] 到 myAuthViewController[或 viewController1] 的展開轉場的簡要說明
這基本上是您通過代碼執行展開轉場的方式。
在要展開到的視圖控制器中實現一個 IBAction 方法(在本例中為 viewController1)。 方法名稱可以是任何長度,只要它需要一個 UIStoryboardSegue 類型的參數。
@IBAction func unwindToMyAuth(segue: UIStoryboardSegue) { println("segue with ID: %@", segue.Identifier) }
將此方法鏈接到要從中放松的 viewController(3) 中。 要鏈接,請右鍵單擊(雙指點擊)viewController 頂部的退出圖標,此時'unwindToMyAuth' 方法將顯示在彈出框中。 控制從該方法單擊到第一個圖標,即 viewController 圖標(也出現在 viewController 的頂部,與退出圖標在同一行)。 選擇彈出的“手動”選項。
在 Document 大綱中,對於同一個視圖 (viewController3),選擇您剛剛創建的 unwind segue。 轉到屬性檢查器並為此展開轉場分配唯一標識符。 我們現在有一個通用的 unwind segue 可以使用了。
現在,展開轉場可以像代碼中的任何其他轉場一樣執行。
performSegueWithIdentifier("unwind.to.myauth", sender: nil)
這種方法會將您從 viewController3 帶到 viewController1,而無需從導航層次結構中刪除 viewController2。
與其他 segue 不同,unwind segue 不會實例化視圖控制器,它們只會轉到導航層次結構中的現有視圖控制器。
正如之前的回答中提到的那樣,彈出不動畫然后推送動畫看起來不太好,因為用戶會看到實際的過程。 我建議你先推送動畫,然后刪除之前的vc。 像這樣:
extension UINavigationController {
func replaceCurrentViewController(with viewController: UIViewController, animated: Bool) {
pushViewController(viewController, animated: animated)
let indexToRemove = viewControllers.count - 2
if indexToRemove >= 0 {
viewControllers.remove(at: indexToRemove)
}
}
}
這是一個快速的 Swift 4/5 解決方案,通過創建一個自定義序列,用新的(無動畫)替換(頂部堆棧)視圖控制器:
class SegueNavigationReplaceTop: UIStoryboardSegue {
override func perform () {
guard let navigationController = source.navigationController else { return }
navigationController.popViewController(animated: false)
navigationController.pushViewController(destination, animated: false)
}
}
使用下面的代碼最后一個視圖控制器你可以使用其他按鈕或把它放在你自己的而不是我用過的取消按鈕
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss:)];
self.navigationItemSetting.leftBarButtonItem = cancelButton;
}
- (IBAction)dismissSettings:(id)sender
{
// your logout code for social media selected
[self.navigationController popToRootViewControllerAnimated:YES];
}
你真正應該做的是模態地呈現一個UINavigationController
包含社交網絡UIViewControllers
在你的菜單UIViewController
之上(如果你願意,它可以嵌入到UINavigationController
)。 然后,一旦用戶通過身份驗證,您就關閉社交網絡UINavigationController
,再次顯示您的菜單UIViewController
。
在swift3
創建一個 segue -add identifier -add 並在 cocoaouch 文件中的 segue(storyboard) 自定義故事板類中設置 -In custom class override perform()
override func perform() {
let sourceViewController = self.source
let destinationController = self.destination
let navigationController = sourceViewController.navigationController
// Pop to root view controller (not animated) before pushing
if self.identifier == "your identifier"{
navigationController?.popViewController(animated: false)
navigationController?.pushViewController(destinationController, animated: true)
}
}
- 您還必須在源視圖控制器中覆蓋一種方法
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
return false
}
這在 Swift 3 中對我有用:
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
if let navVC = source.navigationController {
navVC.pushViewController(destination, animated: true)
} else {
super.perform()
}
}
}
這個怎么樣:)我現在是個老問題,但這會很有用:
UIViewController *destinationController = [[UIViewController alloc] init];
UINavigationController *newNavigation = [[UINavigationController alloc] init];
[newNavigation setViewControllers:@[destinationController]];
[[[UIApplication sharedApplication] delegate] window].rootViewController = newNavigation;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.