Saya memiliki tumpukan navigasi, dengan katakanlah 5 UIViewControllers. Saya ingin menghapus viewcontroller ke-3 dan ke-4 di tumpukan dengan mengklik tombol di viewcontroller ke-5. Apakah mungkin melakukan ini? Jika ya, bagaimana caranya?
iphone
ios
uiviewcontroller
uinavigationcontroller
Jean Paul Scott
sumber
sumber
Pertama-tama Anda bisa mendapatkan semua pengontrol tampilan dalam larik dan kemudian setelah memeriksa dengan kelas pengontrol tampilan yang sesuai, Anda dapat menghapus yang Anda inginkan.
Berikut adalah potongan kecil kode:
NSArray* tempVCA = [self.navigationController viewControllers]; for(UIViewController *tempVC in tempVCA) { if([tempVC isKindOfClass:[urViewControllerClass class]]) { [tempVC removeFromParentViewController]; } }
Saya pikir ini akan membuat pekerjaan Anda lebih mudah.
sumber
Cepat 3 & 4/5
self.navigationController!.viewControllers.removeAll()
self.navigationController?.viewControllers.remove(at: "insert here a number")
Swift 2.1.0
menghapus semua:
self.navigationController!.viewControllers.removeAll()
hapus di indeks
self.navigationController?.viewControllers.removeAtIndex("insert here a number")
Ada banyak tindakan yang lebih mungkin seperti removeFirst, range, dll.
sumber
Cepat 5:
navigationController?.viewControllers.removeAll(where: { (vc) -> Bool in if vc.isKind(of: MyViewController.self) || vc.isKind(of: MyViewController2.self) { return false } else { return true } })
sumber
return !vc.isKind(of: MyViewController.self) && !vc.isKind(of: MyViewController2.self)
akan melakukan pekerjaan dalam satu baris :-)Menggunakan
setViewControllers
fungsi dariUINavigationController
adalah cara terbaik. Ada jugaanimated
parameter untuk mengaktifkan animasi.func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)
Contoh cepat untuk pertanyaan
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) }
Saya mencoba cara lain seperti
[tempVC removeFromParentViewController];
. Itu membuat perilaku aneh, navigasi ViewController yang dihapus masih muncul ketika pop back seperti dilaporkan oleh @ robin-ellerkmannsumber
setViewControllers(_:animated:)
teknik itu dengan dua cara: untuk memunculkan beberapa pengontrol dan untuk mendorong banyak pengontrol.Swift 2.0:
var navArray:Array = (self.navigationController?.viewControllers)! navArray.removeAtIndex(navArray.count-2) self.navigationController?.viewControllers = navArray
sumber
if var navArray = ... { ... }
Swift 5, Xcode 11.3
Saya menemukan pendekatan ini sederhana dengan menentukan pengontrol tampilan mana yang ingin Anda hapus dari tumpukan navigasi.
extension UINavigationController { func removeViewController(_ controller: UIViewController.Type) { if let viewController = viewControllers.first(where: { $0.isKind(of: controller.self) }) { viewController.removeFromParent() } } }
Contoh penggunaan:
navigationController.removeViewController(YourViewController.self)
sumber
Jika Anda mencoba untuk pindah ke pengontrol tampilan ke-2 dari pengontrol tampilan ke-5 (melompati pengontrol tampilan ke-3 dan ke-4), Anda ingin menggunakan
[self.navigationController popToviewController:secondViewController]
.Anda dapat memperolehnya
secondViewController
dari tumpukan pengontrol navigasi.secondViewController = [self.navigationController.viewControllers objectAtIndex:yourViewControllerIndex];
sumber
Gunakan ini
if let navVCsCount = navigationController?.viewControllers.count { navigationController?.viewControllers.removeSubrange(Range(2..<navVCsCount - 1)) }
Ini akan menangani ViewControllers dari navigationController. viewControllers dan juga navigationItems yang ditumpuk di navigationBar.
Catatan: Pastikan untuk memanggilnya setidaknya setelah viewDidAppear
sumber
Swift 5.1, Xcode 11
extension UINavigationController{ public func removePreviousController(total: Int){ let totalViewControllers = self.viewControllers.count self.viewControllers.removeSubrange(totalViewControllers-total..<totalViewControllers - 1) }}
Pastikan untuk memanggil fungsi utilitas ini setelah viewDidDisappear () dari pengontrol sebelumnya atau viewDidAppear () pengontrol baru
sumber
Detail
Larutan
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()!) } }
Pemakaian
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 }
Sampel Lengkap
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 } } }
Hasil
sumber
Solusi ini berhasil untuk saya dalam 4 cepat:
let VCCount = self.navigationController!.viewControllers.count self.navigationController?.viewControllers.removeSubrange(Range(VCCount-3..<VCCount - 1))
indeks pengontrol tampilan Anda saat ini dalam tumpukan adalah:
self.navigationController!.viewControllers.count - 1
sumber
Saya menulis ekstensi dengan metode yang menghapus semua pengontrol antara root dan top, kecuali ditentukan lain.
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) }
}
Kalau mau pakai range (misal: 2 sampai 5) tinggal pakai aja
let range = 2 ..< 5 viewControllers.removeSubrange(range)
Diuji di iOS 12.2, Swift 5
sumber
// menghapus viewcontrollers dengan nama kelas dari tumpukan dan kemudian menutup tampilan saat ini.
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)
sumber