ฉันจะแสดงสองมุมมองพร้อมกันจากตัวควบคุมการนำทางได้อย่างไร


92

ฉันต้องการปรากฏในมุมมองที่สามบนสแต็กการนำทางกลับไปที่มุมมองแรก

ฉันรู้วิธีแสดงหนึ่งมุมมองพร้อมกัน:

[self.navigationController popViewControllerAnimated:YES];

แต่ฉันจะทำสองอย่างพร้อมกันได้อย่างไร?


2
ความคิดเห็นเมตา: @lubilis คำตอบที่ดีที่สุดคือ คำตอบที่ได้รับคะแนนสูงสุดเป็นสิ่งที่ดีในเวลานั้น แต่ไม่เกี่ยวข้องอีกต่อไป
13

คำตอบ:


133

คุณสามารถลองสิ่งนี้เพื่อข้ามไปมาระหว่างสแต็กตัวควบคุมการนำทางได้เช่นกัน

NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
    if ([aViewController isKindOfClass:[RequiredViewController class]]) {
        [self.navigationController popToViewController:aViewController animated:NO];
    }
}

6
imo นี่เป็นวิธีที่ดีที่สุด แต่คุณควรอ้างอิงตัวควบคุม uinavigation ของคุณโดยใช้ self.navigationcontroller
henghonglee

2
ฉันเห็นด้วยนี่เป็นวิธีแก้ปัญหาที่ดีที่สุดหากผู้ใช้ต้องการเปิดสแต็กกลับไปที่ตัวควบคุมมุมมองบางตัว สมมติว่าคุณไม่ทราบว่า viewcontrollers คืออะไรคุณยังสามารถใช้ระบบที่คุณจะระบุจำนวน viewcontrollers ที่คุณต้องการจะเปิดออกจาก stack และรับ viewcontroller เป้าหมายจากอาร์เรย์ allViewControllers พร้อม objectAtIndex: (allViewControllers.count - 1 - จำนวนเงิน) -1 เนื่องจากอาร์เรย์เป็นศูนย์ตามหลักสูตร
Jovan

1
รักโซลูชันนี้ สิ่งที่ฉันกำลังมองหา
Designer023

3
ทำงานได้เช่นกันเมื่อทำซ้ำบนอาร์เรย์ navigator-> viewControllers ดั้งเดิม (ไม่จำเป็นต้องแปลงเป็นอาร์เรย์ที่ไม่แน่นอน)
Arik Segal

บันทึก! สิ่งนี้จะวนซ้ำสแต็กจากจุดเริ่มต้น -> ไปยังจุดสิ้นสุดเพื่อให้ถูกต้องคุณควรย้อนกลับสแต็ก เพราะถ้าคุณมี VC หลายตัวที่เหมือนกันคุณจะลบ VC ผิดลำดับที่ไม่ถูกต้องในสแตก
StackUnderflow

72

นี่คือสองUINavigationControllerส่วนขยายที่สามารถแก้ปัญหาของคุณได้ ฉันขอแนะนำให้ใช้อันแรกที่ปรากฏในUIViewControllerคลาสเฉพาะ:

extension UINavigationController {

  func popToViewController(ofClass: AnyClass, animated: Bool = true) {
    if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
      popToViewController(vc, animated: animated)
    }
  }

  func popViewControllers(viewsToPop: Int, animated: Bool = true) {
    if viewControllers.count > viewsToPop {
      let vc = viewControllers[viewControllers.count - viewsToPop - 1]
      popToViewController(vc, animated: animated)
    }
  }

}

และใช้มันดังนี้:

// pop to SomeViewController class
navigationController?.popToViewController(ofClass: SomeViewController.self)

// pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)

3
สำหรับ Swift (ตัวเลือก 1) คุณสามารถแทนที่ทั้งสองremoveLastด้วยเพียงremoveLast(2).
Dominic K

สิ่งที่เกี่ยวกับการเรียกวิธีการของวงจรชีวิตของคอนโทรลเลอร์? DidAppear และอื่น ๆ
Mike Glukhov

1
(Swift 4) คุณไม่มีวงเล็บในบรรทัดนี้let vc = viewControllers[viewControllers.count - viewsToPop + 1]เพื่อให้ทำงานได้อย่างถูกต้องคุณต้องแทนที่ด้วย: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]หรือlet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@MMiroslav คุณพูดถูก ฉันได้อัปเดตคำตอบแล้ว ขอบคุณ / Hvala;)
budidino

1
คำตอบนี้ได้รับการอัปเดตหลังจากที่ฉันโพสต์คำตอบด้านล่าง โดยพื้นฐานแล้วสำเนารหัสของฉัน ^ _ ^
lubilis

44

คุณสามารถไปที่ตัวควบคุมมุมมอง "root" (ตัวแรก) ด้วยpopToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

// If you want to know what view controllers were popd:
// NSArray *popdViewControllers = [self.navigationController popToRootViewControllerAnimated:YES];

UINavigationControllerอ้างอิง :

แสดงตัวควบคุมมุมมองทั้งหมดบนสแต็กยกเว้นตัวควบคุมมุมมองรูทและอัปเดตการแสดงผล

Return Value
อาร์เรย์ของตัวควบคุมมุมมองที่ดึงมาจากสแตก


1
ฮ่าไม่อยากจะเชื่อเลยว่าฉันใช้เวลานานมากในการหาคำตอบง่ายๆแบบนี้ขอบคุณ!
Adam Waite

1
Swift 3: self.navigationController? .popToRootViewController (ภาพเคลื่อนไหว: จริง);
dianakarenms

สิ่งที่ฉันกำลังมองหาอย่างแม่นยำ!
Canucklesandwich

29
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

objectAtIndex: 1 -> คุณสามารถส่งดัชนีใดก็ได้ที่คุณต้องการปรากฏขึ้น


ขอบคุณสำหรับเคล็ดลับฉันกำลังจะทำในทางที่ผิด
Linus

18

Swift 2 - xCode 7.3

นี่อาจเป็นส่วนขยายที่มีประโยชน์มากในการป๊อป UIViewControllers:

extension UINavigationController {

    func popToViewControllerOfType(classForCoder: AnyClass) {
        for controller in viewControllers {
            if controller.classForCoder == classForCoder {
                popToViewController(controller, animated: true)
                break
            }
        }
    }

    func popViewControllers(controllersToPop: Int, animated: Bool) {
        if viewControllers.count > controllersToPop {
            popToViewController(viewControllers[viewControllers.count - (controllersToPop + 1)], animated: animated)
        } else {
            print("Trying to pop \(controllersToPop) view controllers but navigation controller contains only \(viewControllers.count) controllers in stack")
        }
    }
}

2
สิ่งนี้ต้องการการโหวตเพิ่มขึ้น .. . ฉันกำลังจะเขียนส่วนขยายนั้น ฉันจะใช้ของคุณขอบคุณ;)
13

1
@ n13 ทำไมถึงดีกว่าคำตอบของ budidino?
Crashalot

1
การใช้ส่วนขยายทำให้โค้ดสะอาดขึ้นมาก คุณสามารถใช้คำตอบของ budidino และขยายความได้ แต่คำตอบนี้ช่วยให้คุณประหยัดได้ นอกจากนี้คำตอบนี้ยังตรวจสอบกรณีข้อผิดพลาดและจัดการข้อผิดพลาดอย่างสง่างาม (เช่นพยายามที่จะปรากฏมากกว่าที่คุณมี)
n13

1
ฉันชอบคำตอบนี้ ทำให้ฉันคิดใหม่และอัปเดตคำตอบที่ฉันโพสต์ ฉันทำให้โค้ดของฉันปรากฏในอินสแตนซ์สุดท้ายของคลาสที่ค้นหาในอาร์เรย์ viewControllers เพราะนั่นอาจเป็นพฤติกรรมที่ต้องการ
budidino

15

หากคุณต้องการป๊อป 2 พร้อมกันเนื่องจาก rootViewController ของคุณ (ทาง) 'ลึกกว่า' ดังนั้น 2 คุณสามารถพิจารณาเพิ่มหมวดหมู่ให้กับ UIviewController ได้เช่น:

UINavigationController + popTwice.h

#import <UIKit/UIKit.h>
@interface UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated;

@end

UINavigationController + popTwice.m

#import "UINavigationController+popTwice.h"

@implementation UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated{
    [self popViewControllerAnimated:NO];
    [self popViewControllerAnimated:animated];
}

@end

นำเข้าหมวดหมู่#import "UINavigationController+popTwice.h"ใดที่หนึ่งในการใช้งานของคุณและใช้บรรทัดของโค้ดนี้เพื่อเปิดตัวควบคุม 2 ตัวพร้อมกัน:

[self.navigationController popTwoViewControllersAnimated:YES];

ไม่ดีเหรอ? :)


6
จะเป็นอย่างไรถ้าคุณต้องการป๊อป 3 มุมมองคุณจะเขียนว่า "UINavigationController + popThrice.m" ??????
พบกัน

8
คุณสามารถส่งพารามิเตอร์สำหรับจำนวน viewControllers ที่จะป๊อปและตัด [self popViewControllerAnimate: NO]; ภายใน for-loop ของ count-1
noRema

นี่ไม่ใช่วิธีที่ถูกต้องหากคุณต้องการหม้อเป็น 2,3, ... คอนโทรลเลอร์ใด ๆ ระบุมันด้วยลูปแล้วใช้ [self.navigationController popToViewControllerAnimate: YES]; ที่กล่าวมาข้างต้นนี้เป็นการเข้ารหัสที่ไม่ดีมากและอาจแสดง UI ที่ไม่แน่นอนและประสบการณ์ของผู้ใช้ที่ไม่ดี
Vicky Dhas

10

Swift 4:

func popViewControllerss(popViews: Int, animated: Bool = true) {
    if self.navigationController!.viewControllers.count > popViews
    {
        let vc = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - popViews - 1]
         self.navigationController?.popToViewController(vc, animated: animated)
    }
}

จากนั้นใช้วิธีนี้

self.popViewControllerss(popViews: 2)

ดีสิ่งที่ฉันกำลังมองหา ขอบคุณ.
maddysan


6
//viewIndex = 1;
//viewIndex = 2;
//viewIndex = 3;

// **[viewControllers objectAtIndex: *put here your viewindex number*]

NSArray *viewControllers = [self.navigationController viewControllers];
[self.navigationController popToViewController:[viewControllers objectAtIndex:viewIndex] animated:NO];


4

ใน Swift 3คุณสามารถเปิดตัวควบคุมมุมมองหนึ่งสองตัวขึ้นไปจากตัวควบคุมการนำทางเช่นนั้น

let viewControllers = self.navigationController!.viewControllers as [UIViewController]
    for aViewController:UIViewController in viewControllers {
        if aViewController.isKind(of: FromWhereYouWantToGoController.self) {
            _ = self.navigationController?.popToViewController(aViewController, animated: true)
        }
    }

ที่นี่ FromWhereYouWantToGoController คือตัวควบคุมปลายทาง หวังว่าจะช่วยได้


3

คุณสามารถส่งตัวควบคุมมุมมองเริ่มต้น (ตัวควบคุมที่คุณต้องการกลับมา) จากนั้นเรียกบรรทัดนี้ในมุมมองสุดท้าย:

[self.navigationController popToViewController:yourInitialViewController animated:YES];

ล.


3

ฉันไม่เห็นคำตอบนี้ที่นี่ หากคุณต้องการป๊อปอัพเพียงไม่กี่รายการ (ไม่ใช่ทั้งหมดไปที่รูท) คุณสามารถทำซ้ำผ่าน self.navigationController.viewControllers เพื่อตรวจสอบประเภทคลาสหรือหากคุณมีการอ้างอิงให้ใช้:

for (UIViewController *aViewController in self.navigationController.viewControllers) {
   if ([aViewController isKindOfClass:[SMThumbnailViewController class]]) {
      [self.navigationController popToViewController:aViewController animated:YES];
   }
}

2

คุณสามารถกลับไปที่ตัวควบคุมมุมมองรูท

[self.navigationController popToRootViewControllerAnimated:YES];

หรือหากมุมมองที่คุณต้องการให้ปรากฏไม่ใช่มุมมองแรกคุณจะต้องปรากฏขึ้นอีกครั้งในมุมมองก่อนหน้านี้


2

นี่คือฟังก์ชั่นเล็กน้อยที่ฉันใช้เพื่อย้อนกลับ X ViewControllers:

-(void)backMultiple:(id)data {
    int back = 2; //Default to go back 2 
    int count = [self.navigationController.viewControllers count];

    if(data[@"count"]) back = [data[@"count"] intValue];

    //If we want to go back more than those that actually exist, just go to the root
    if(back+1 > count) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    //Otherwise go back X ViewControllers 
    else {
        [self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:count-(back+1)] animated:YES];
    }
}

2

เวอร์ชัน Swift ณ (Swift 1.2 / Xcode 6.3.1) ของ popping สองครั้งขึ้นไป

 var viewControllers = self.navigationController?.viewControllers
 viewControllers?.removeLast()
 viewControllers?.removeLast()
 self.navigationController?.setViewControllers(viewControllers, animated: true)

หรือ

 var viewControllers = self.navigationController?.viewControllers
 var viewsToPop = 2
 var end = (viewControllers?.count)!
 var start = end - viewsToPop
 viewControllers?.removeRange(Range<Int>(start: start, end: end))
 self.navigationController?.setViewControllers(viewControllers, animated: true)

1

คุณสามารถใช้สแต็กของ UIViewControllers 1. ดึงอาร์เรย์ของ viewControllers ทั้งหมดในสแต็ก 2. วนซ้ำอาร์เรย์ทั้งหมดและค้นหา viewController ที่ต้องการ
โดยจับคู่ประเภทคลาส 3. เปิด viewController

func popToSpecificViewC
{
let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController];
        for viewController:UIViewController in viewControllers
        {
            if viewController.isKind(of: WelcomeViewC.self)
            {
                _ = self.navigationController?.popToViewController(viewController, animated: true)
            }
        }
}

0

ใช้ส่วนขยาย UINavigationControllerง่ายๆ:

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.