ฉันมีสแต็กการนำทางพร้อมด้วย UIViewControllers 5 ตัว ฉันต้องการลบตัวควบคุมวิวตัวที่ 3 และ 4 ในสแต็กเมื่อคลิกปุ่มในตัวควบคุมวิวตัวที่ 5 เป็นไปได้ไหมที่จะทำเช่นนี้? ถ้าเป็นอย่างไร
ฉันมีสแต็กการนำทางพร้อมด้วย UIViewControllers 5 ตัว ฉันต้องการลบตัวควบคุมวิวตัวที่ 3 และ 4 ในสแต็กเมื่อคลิกปุ่มในตัวควบคุมวิวตัวที่ 5 เป็นไปได้ไหมที่จะทำเช่นนี้? ถ้าเป็นอย่างไร
คำตอบ:
ใช้รหัสนี้และเพลิดเพลินกับ:
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
// [navigationArray removeAllObjects]; // This is just for remove all view controller from navigation stack.
[navigationArray removeObjectAtIndex: 2]; // You can pass your index here
self.navigationController.viewControllers = navigationArray;
[navigationArray release];
หวังว่านี่จะช่วยคุณได้
แก้ไข: Swift Code
guard let navigationController = self.navigationController else { return }
var navigationArray = navigationController.viewControllers // To get all UIViewController stack as Array
navigationArray.remove(at: navigationArray.count - 2) // To remove previous UIViewController
self.navigationController?.viewControllers = navigationArray
ก่อนอื่นคุณสามารถรับตัวควบคุมมุมมองทั้งหมดในอาร์เรย์จากนั้นหลังจากตรวจสอบกับคลาสตัวควบคุมมุมมองที่เกี่ยวข้องแล้วคุณสามารถลบตัวควบคุมที่คุณต้องการได้
นี่คือโค้ดชิ้นเล็ก ๆ :
NSArray* tempVCA = [self.navigationController viewControllers];
for(UIViewController *tempVC in tempVCA)
{
if([tempVC isKindOfClass:[urViewControllerClass class]])
{
[tempVC removeFromParentViewController];
}
}
ฉันคิดว่านี่จะทำให้งานของคุณง่ายขึ้น
Swift 3 และ 4/5
self.navigationController!.viewControllers.removeAll()
self.navigationController?.viewControllers.remove(at: "insert here a number")
Swift 2.1
ลบทั้งหมด:
self.navigationController!.viewControllers.removeAll()
ลบที่ดัชนี
self.navigationController?.viewControllers.removeAtIndex("insert here a number")
มีการดำเนินการที่เป็นไปได้มากมายเช่น removeFirst, range ฯลฯ
สวิฟต์ 5:
navigationController?.viewControllers.removeAll(where: { (vc) -> Bool in
if vc.isKind(of: MyViewController.self) || vc.isKind(of: MyViewController2.self) {
return false
} else {
return true
}
})
return !vc.isKind(of: MyViewController.self) && !vc.isKind(of: MyViewController2.self)
จะทำงานในบรรทัดเดียว :-)
การใช้setViewControllers
ฟังก์ชันจากUINavigationController
เป็นวิธีที่ดีที่สุด นอกจากนี้ยังมีanimated
พารามิเตอร์เพื่อเปิดใช้งานภาพเคลื่อนไหว
func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)
ตัวอย่างรวดเร็วสำหรับคำถาม
func goToFifthVC() {
var currentVCStack = self.navigationController?.viewControllers
currentVCStack?.removeSubrange(2...3)
let fifthVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "fifthVC")
currentVCStack?.append(fifthVC)
self.navigationController?.setViewControllers(currentVCStack!, animated: true)
}
ฉันลองวิธีอื่น ๆ เช่น[tempVC removeFromParentViewController];
. มันทำให้พฤติกรรมแปลก ๆ การนำทาง ViewController ที่ถูกลบยังคงแสดงเมื่อป๊อปกลับเหมือนรายงานโดย @ robin-ellerkmann
setViewControllers(_:animated:)
เทคนิคนั้นทั้งสองวิธี: เพื่อเปิดตัวควบคุมหลายตัวและเพื่อผลักตัวควบคุมหลายตัว
Swift 2.0:
var navArray:Array = (self.navigationController?.viewControllers)!
navArray.removeAtIndex(navArray.count-2)
self.navigationController?.viewControllers = navArray
if var navArray = ... { ... }
Swift 5, Xcode 11.3
ฉันพบว่าวิธีนี้ง่ายโดยการระบุตัวควบคุมมุมมองที่คุณต้องการลบออกจากสแต็กการนำทาง
extension UINavigationController {
func removeViewController(_ controller: UIViewController.Type) {
if let viewController = viewControllers.first(where: { $0.isKind(of: controller.self) }) {
viewController.removeFromParent()
}
}
}
ตัวอย่างการใช้งาน:
navigationController.removeViewController(YourViewController.self)
หากคุณกำลังพยายามที่จะย้ายไปยังตัวควบคุมมุมมองที่ 2 จากตัวควบคุมมุมมองที่ 5 (ข้ามไปที่ 3 และ 4) คุณต้องการใช้ [self.navigationController popToviewController:secondViewController]
คุณต้องการที่จะใช้
คุณสามารถรับsecondViewController
จากกองควบคุมการนำทาง
secondViewController = [self.navigationController.viewControllers objectAtIndex:yourViewControllerIndex];
ใช้สิ่งนี้
if let navVCsCount = navigationController?.viewControllers.count {
navigationController?.viewControllers.removeSubrange(Range(2..<navVCsCount - 1))
}
มันจะดูแล ViewControllers ของ navigationController viewControllers และ navigationItems ซ้อนกันใน navigationBar
หมายเหตุ: อย่าลืมเรียกมันอย่างน้อยหลัง viewDidAppear
Swift 5.1, Xcode 11
extension UINavigationController{
public func removePreviousController(total: Int){
let totalViewControllers = self.viewControllers.count
self.viewControllers.removeSubrange(totalViewControllers-total..<totalViewControllers - 1)
}}
ตรวจสอบให้แน่ใจว่าได้เรียกใช้ฟังก์ชันยูทิลิตี้นี้หลังจาก viewDidDisappear () ของคอนโทรลเลอร์ก่อนหน้าหรือ viewDidAppear () ของคอนโทรลเลอร์ใหม่
extension UIViewController {
func removeFromNavigationController() { navigationController?.removeController(.last) { self == $0 } }
}
extension UINavigationController {
enum ViewControllerPosition { case first, last }
enum ViewControllersGroupPosition { case first, last, all }
func removeController(_ position: ViewControllerPosition, animated: Bool = true,
where closure: (UIViewController) -> Bool) {
var index: Int?
switch position {
case .first: index = viewControllers.firstIndex(where: closure)
case .last: index = viewControllers.lastIndex(where: closure)
}
if let index = index { removeControllers(animated: animated, in: Range(index...index)) }
}
func removeControllers(_ position: ViewControllersGroupPosition, animated: Bool = true,
where closure: (UIViewController) -> Bool) {
var range: Range<Int>?
switch position {
case .first: range = viewControllers.firstRange(where: closure)
case .last:
guard let _range = viewControllers.reversed().firstRange(where: closure) else { return }
let count = viewControllers.count - 1
range = .init(uncheckedBounds: (lower: count - _range.min()!, upper: count - _range.max()!))
case .all:
let viewControllers = self.viewControllers.filter { !closure($0) }
setViewControllers(viewControllers, animated: animated)
return
}
if let range = range { removeControllers(animated: animated, in: range) }
}
func removeControllers(animated: Bool = true, in range: Range<Int>) {
var viewControllers = self.viewControllers
viewControllers.removeSubrange(range)
setViewControllers(viewControllers, animated: animated)
}
func removeControllers(animated: Bool = true, in range: ClosedRange<Int>) {
removeControllers(animated: animated, in: Range(range))
}
}
private extension Array {
func firstRange(where closure: (Element) -> Bool) -> Range<Int>? {
guard var index = firstIndex(where: closure) else { return nil }
var indexes = [Int]()
while index < count && closure(self[index]) {
indexes.append(index)
index += 1
}
if indexes.isEmpty { return nil }
return Range<Int>(indexes.min()!...indexes.max()!)
}
}
removeFromParent()
navigationController?.removeControllers(in: 1...3)
navigationController?.removeController(.first) { $0 != self }
navigationController?.removeController(.last) { $0 != self }
navigationController?.removeControllers(.all) { $0.isKind(of: ViewController.self) }
navigationController?.removeControllers(.first) { !$0.isKind(of: ViewController.self) }
navigationController?.removeControllers(.last) { $0 != self }
อย่าลืมวางรหัสโซลูชันที่นี่
import UIKit
class ViewController2: ViewController {}
class ViewController: UIViewController {
private var tag: Int = 0
deinit { print("____ DEINITED: \(self), tag: \(tag)" ) }
override func viewDidLoad() {
super.viewDidLoad()
print("____ INITED: \(self)")
let stackView = UIStackView()
stackView.axis = .vertical
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackView.addArrangedSubview(createButton(text: "Push ViewController() white", selector: #selector(pushWhiteViewController)))
stackView.addArrangedSubview(createButton(text: "Push ViewController() gray", selector: #selector(pushGrayViewController)))
stackView.addArrangedSubview(createButton(text: "Push ViewController2() green", selector: #selector(pushController2)))
stackView.addArrangedSubview(createButton(text: "Push & remove previous VC", selector: #selector(pushViewControllerAndRemovePrevious)))
stackView.addArrangedSubview(createButton(text: "Remove first gray VC", selector: #selector(dropFirstGrayViewController)))
stackView.addArrangedSubview(createButton(text: "Remove last gray VC", selector: #selector(dropLastGrayViewController)))
stackView.addArrangedSubview(createButton(text: "Remove all gray VCs", selector: #selector(removeAllGrayViewControllers)))
stackView.addArrangedSubview(createButton(text: "Remove all VCs exept Last", selector: #selector(removeAllViewControllersExeptLast)))
stackView.addArrangedSubview(createButton(text: "Remove all exept first and last VCs", selector: #selector(removeAllViewControllersExeptFirstAndLast)))
stackView.addArrangedSubview(createButton(text: "Remove all ViewController2()", selector: #selector(removeAllViewControllers2)))
stackView.addArrangedSubview(createButton(text: "Remove first VCs where bg != .gray", selector: #selector(dropFirstViewControllers)))
stackView.addArrangedSubview(createButton(text: "Remove last VCs where bg == .gray", selector: #selector(dropLastViewControllers)))
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if title?.isEmpty ?? true { title = "First" }
}
private func createButton(text: String, selector: Selector) -> UIButton {
let button = UIButton()
button.setTitle(text, for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: selector, for: .touchUpInside)
return button
}
}
extension ViewController {
private func createViewController<VC: ViewController>(backgroundColor: UIColor = .white) -> VC {
let viewController = VC()
let counter = (navigationController?.viewControllers.count ?? -1 ) + 1
viewController.tag = counter
viewController.title = "Controller \(counter)"
viewController.view.backgroundColor = backgroundColor
return viewController
}
@objc func pushWhiteViewController() {
navigationController?.pushViewController(createViewController(), animated: true)
}
@objc func pushGrayViewController() {
navigationController?.pushViewController(createViewController(backgroundColor: .lightGray), animated: true)
}
@objc func pushController2() {
navigationController?.pushViewController(createViewController(backgroundColor: .green) as ViewController2, animated: true)
}
@objc func pushViewControllerAndRemovePrevious() {
navigationController?.pushViewController(createViewController(), animated: true)
removeFromNavigationController()
}
@objc func removeAllGrayViewControllers() {
navigationController?.removeControllers(.all) { $0.view.backgroundColor == .lightGray }
}
@objc func removeAllViewControllersExeptLast() {
navigationController?.removeControllers(.all) { $0 != self }
}
@objc func removeAllViewControllersExeptFirstAndLast() {
guard let navigationController = navigationController, navigationController.viewControllers.count > 1 else { return }
let lastIndex = navigationController.viewControllers.count - 1
navigationController.removeControllers(in: 1..<lastIndex)
}
@objc func removeAllViewControllers2() {
navigationController?.removeControllers(.all) { $0.isKind(of: ViewController2.self) }
}
@objc func dropFirstViewControllers() {
navigationController?.removeControllers(.first) { $0.view.backgroundColor != .lightGray }
}
@objc func dropLastViewControllers() {
navigationController?.removeControllers(.last) { $0.view.backgroundColor == .lightGray }
}
@objc func dropFirstGrayViewController() {
navigationController?.removeController(.first) { $0.view.backgroundColor == .lightGray }
}
@objc func dropLastGrayViewController() {
navigationController?.removeController(.last) { $0.view.backgroundColor == .lightGray }
}
}
วิธีนี้ใช้ได้ผลสำหรับฉันใน swift 4:
let VCCount = self.navigationController!.viewControllers.count
self.navigationController?.viewControllers.removeSubrange(Range(VCCount-3..<VCCount - 1))
ดัชนีคอนโทรลเลอร์มุมมองปัจจุบันของคุณในสแต็กคือ:
self.navigationController!.viewControllers.count - 1
ฉันเขียนส่วนขยายด้วยวิธีการที่จะลบตัวควบคุมทั้งหมดระหว่างรูทและบนสุดเว้นแต่จะระบุไว้เป็นอย่างอื่น
extension UINavigationController {
func removeControllers(between start: UIViewController?, end: UIViewController?) {
guard viewControllers.count > 1 else { return }
let startIndex: Int
if let start = start {
guard let index = viewControllers.index(of: start) else {
return
}
startIndex = index
} else {
startIndex = 0
}
let endIndex: Int
if let end = end {
guard let index = viewControllers.index(of: end) else {
return
}
endIndex = index
} else {
endIndex = viewControllers.count - 1
}
let range = startIndex + 1 ..< endIndex
viewControllers.removeSubrange(range)
}
}
หากคุณต้องการใช้ช่วง (เช่น 2 ถึง 5) คุณสามารถใช้ได้
let range = 2 ..< 5
viewControllers.removeSubrange(range)
ทดสอบบน iOS 12.2, Swift 5
// ลบ viewcontrollers ตามชื่อคลาสออกจากสแต็กแล้วปิดมุมมองปัจจุบัน
self.navigationController?.viewControllers.removeAll(where: { (vc) -> Bool in
if vc.isKind(of: ViewController.self) || vc.isKind(of: ViewController2.self)
{
return true
}
else
{
return false
}
})
self.navigationController?.popViewController(animated: false)
self.dismiss(animated: true, completion: nil)