簡體   English   中英

而不是 push segue 如何替換視圖控制器(或從導航堆棧中刪除)?

[英]Instead of push segue how to replace view controller (or remove from navigation stack)?

我有一個小型 iPhone 應用程序,它使用導航控制器顯示 3 個視圖(此處為全屏):

Xcode 截圖

首先它顯示社交網絡列表(Facebook、Google+ 等):

列表截圖

然后它會顯示一個 OAuth 對話框,要求提供憑據:

登錄截圖

並且(之后,在同一個UIWebView )獲取權限:

權限截圖

最后,它顯示帶有用戶詳細信息的最后一個視圖控制器(在實際應用程序中,這將是菜單,可以在其中啟動多人游戲):

詳情截圖

這一切都很好,但我有一個問題,當用戶想要返回並選擇另一個社交網絡時:

用戶觸摸后退按鈕,而不是顯示第一個視圖,而是顯示第二個視圖,再次請求 OAuth 憑據/權限。

我能在這里做什么? Xcode 5.0.2 顯示了一個非常有限的 segues 選擇 - pushmodal (我不能使用,因為它掩蓋了我的游戲所需的導航欄)和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)
    }
}

對於這個問題,我認為答案很簡單

  1. 從 NavigationController 獲取視圖控制器數組
  2. 刪除最后一個 ViewController(當前視圖控制器)
  3. 最后插入一個新的
  4. 然后將 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
}

好吧,你還可以做的是使用展開視圖控制器的東西。

其實我認為這正是你所需要的。

檢查此條目: Unwind segue 的用途是什么以及如何使用它們?

這在 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM