Tôi có một ngăn xếp điều hướng, với 5 UIViewControllers. Tôi muốn xóa bộ điều khiển chế độ xem thứ 3 và thứ 4 trong ngăn xếp bằng cách nhấp vào nút trong bộ điều khiển chế độ xem thứ 5. có khả năng làm cái này không? Nếu vậy thì làm thế nào?
Tôi có một ngăn xếp điều hướng, với 5 UIViewControllers. Tôi muốn xóa bộ điều khiển chế độ xem thứ 3 và thứ 4 trong ngăn xếp bằng cách nhấp vào nút trong bộ điều khiển chế độ xem thứ 5. có khả năng làm cái này không? Nếu vậy thì làm thế nào?
Câu trả lời:
Sử dụng mã này và tận hưởng:
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];
Hy vọng điều này sẽ giúp bạn.
Chỉnh sửa: Mã Swift
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
Trước tiên, bạn có thể lấy tất cả các bộ điều khiển chế độ xem trong mảng và sau đó sau khi kiểm tra với lớp bộ điều khiển chế độ xem tương ứng, bạn có thể xóa lớp bạn muốn.
Đây là đoạn mã nhỏ:
NSArray* tempVCA = [self.navigationController viewControllers];
for(UIViewController *tempVC in tempVCA)
{
if([tempVC isKindOfClass:[urViewControllerClass class]])
{
[tempVC removeFromParentViewController];
}
}
Tôi nghĩ rằng điều này sẽ làm cho công việc của bạn dễ dàng hơn.
Swift 3 & 4/5
self.navigationController!.viewControllers.removeAll()
self.navigationController?.viewControllers.remove(at: "insert here a number")
Swift 2.1
xóa tất cả:
self.navigationController!.viewControllers.removeAll()
loại bỏ tại chỉ mục
self.navigationController?.viewControllers.removeAtIndex("insert here a number")
Có nhiều hành động khả thi hơn như removeFirst, range, v.v.
Swift 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)
sẽ thực hiện công việc trong một dòng :-)
Sử dụng setViewControllers
chức năng từ UINavigationController
là cách tốt nhất. Ngoài ra còn có animated
tham số để kích hoạt hoạt ảnh.
func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)
Ví dụ trong nhanh chóng cho câu hỏi
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)
}
Tôi đã thử những cách khác như [tempVC removeFromParentViewController];
. Nó tạo ra hành vi kỳ lạ, điều hướng ViewController bị loại bỏ vẫn hiển thị khi bật lại như được @ robin-ellerkmann báo cáo
setViewControllers(_:animated:)
kỹ thuật đó theo cả hai cách: để bật nhiều bộ điều khiển và đẩy nhiều bộ điều khiển.
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
Tôi thấy cách tiếp cận này đơn giản bằng cách chỉ định (các) bộ điều khiển chế độ xem bạn muốn loại bỏ khỏi ngăn xếp điều hướng.
extension UINavigationController {
func removeViewController(_ controller: UIViewController.Type) {
if let viewController = viewControllers.first(where: { $0.isKind(of: controller.self) }) {
viewController.removeFromParent()
}
}
}
Ví dụ sử dụng:
navigationController.removeViewController(YourViewController.self)
Nếu bạn đang cố gắng chuyển sang bộ điều khiển chế độ xem thứ 2 từ bộ điều khiển chế độ xem thứ 5 (bỏ qua bộ điều khiển chế độ xem thứ 3 và thứ 4), bạn muốn sử dụng [self.navigationController popToviewController:secondViewController]
.
Bạn có thể lấy secondViewController
từ ngăn xếp bộ điều khiển điều hướng.
secondViewController = [self.navigationController.viewControllers objectAtIndex:yourViewControllerIndex];
Dùng cái này
if let navVCsCount = navigationController?.viewControllers.count {
navigationController?.viewControllers.removeSubrange(Range(2..<navVCsCount - 1))
}
Nó sẽ chăm sóc các ViewControllers của navigationController. viewControllers và cả một navigationItems được xếp chồng lên nhau trong navigationBar.
Lưu ý: Hãy chắc chắn gọi nó ít nhất sau viewDidAppear
Giải pháp này đã làm việc cho tôi trong nhanh chóng 4:
let VCCount = self.navigationController!.viewControllers.count
self.navigationController?.viewControllers.removeSubrange(Range(VCCount-3..<VCCount - 1))
chỉ số bộ điều khiển chế độ xem hiện tại của bạn trong ngăn xếp là:
self.navigationController!.viewControllers.count - 1
Swift 5.1, Xcode 11
extension UINavigationController{
public func removePreviousController(total: Int){
let totalViewControllers = self.viewControllers.count
self.viewControllers.removeSubrange(totalViewControllers-total..<totalViewControllers - 1)
}}
Đảm bảo gọi hàm tiện ích này sau viewDidDisappear () của bộ điều khiển trước đó hoặc viewDidAppear () của bộ điều khiển mới
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 }
Đừng quên dán mã giải pháp vào đây
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 }
}
}
Tôi đã viết một phần mở rộng với phương thức loại bỏ tất cả các bộ điều khiển giữa gốc và trên cùng, trừ khi được chỉ định khác.
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)
}
}
Nếu bạn muốn sử dụng phạm vi (ví dụ: 2 đến 5), bạn chỉ có thể sử dụng
let range = 2 ..< 5
viewControllers.removeSubrange(range)
Đã thử nghiệm trên iOS 12.2, Swift 5
// loại bỏ các bộ điều khiển chế độ xem theo tên lớp khỏi ngăn xếp và sau đó loại bỏ chế độ xem hiện tại.
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)