เป็นไปได้หรือไม่ที่จะตรวจสอบภายในคลาส ViewController ที่แสดงเป็นตัวควบคุมมุมมองแบบโมดอล
เป็นไปได้หรือไม่ที่จะตรวจสอบภายในคลาส ViewController ที่แสดงเป็นตัวควบคุมมุมมองแบบโมดอล
คำตอบ:
เนื่องจากmodalViewController
ได้เลิกใช้งานใน iOS 6 แล้วนี่คือเวอร์ชันที่ใช้งานได้กับ iOS 5+ และจะรวบรวมโดยไม่มีคำเตือน
Objective-C:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
สวิฟท์:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
เคล็ดลับสำหรับคำตอบของเฟลิเป้
nil == nil
ผลตอบแทนYES
ไม่ใช่ผลลัพธ์ที่เราต้องการ
หากคุณกำลังมองหา iOS 6+ คำตอบนี้เลิกใช้แล้วและคุณควรตรวจสอบคำตอบของ Gabriele Petronella
ไม่มีวิธีใดที่จะทำได้อย่างเป็นระเบียบเนื่องจากเป็นคุณสมบัติหรือวิธีการดั้งเดิมของ UIKit สิ่งที่คุณทำได้คือตรวจสอบหลาย ๆ ด้านของคอนโทรลเลอร์เพื่อให้แน่ใจว่าถูกนำเสนอเป็นโมดอล
ดังนั้นเพื่อตรวจสอบว่าตัวควบคุมปัจจุบัน (แสดงเป็นself
รหัสร้อง) ถูกนำเสนอในรูปแบบโมดอลหรือไม่ฉันมีฟังก์ชั่นดังต่อไปนี้ในUIViewController
หมวดหมู่หรือ (หากโครงการของคุณไม่จำเป็นต้องใช้คอนโทรลเลอร์ UIKit อื่นเช่นUITableViewController
ตัวอย่าง) ในตัวควบคุมพื้นฐานที่ตัวควบคุมอื่น ๆ ของฉันสืบทอดมา
-(BOOL)isModal {
BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) ||
//or if I have a navigation controller, check if its parent modal view controller is self navigation controller
( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) ||
//or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
[[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);
//iOS 5+
if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {
isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) ||
//or if I have a navigation controller, check if its parent modal view controller is self navigation controller
(self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) ||
//or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
[[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);
}
return isModal;
}
แก้ไข: ฉันเพิ่มการตรวจสอบครั้งสุดท้ายเพื่อดูว่ามีการใช้ UITabBarController หรือไม่และคุณนำเสนอ UITabBarController อื่นเป็นโมดอล
แก้ไข 2: เพิ่มการตรวจสอบ iOS 5+ ซึ่งUIViewController
ไม่ตอบโจทย์parentViewController
อีกต่อไป แต่เป็นpresentingViewController
แทน
แก้ไข 3: ฉันได้สร้างส่วนสำคัญสำหรับมันในกรณีที่https://gist.github.com/3174081
modalViewController
คุณสมบัตินี้เลิกใช้แล้วใน iOS 6 เอกสารแนะนำให้ใช้presentedViewController
แทน
NSLog(@"%@", self.navigationController.parentViewController)
พิมพ์(null)
- คุณช่วยอธิบายว่าทำไม My ViewController เชื่อมต่อกับ modal view controller ผ่าน navController ใน storyboard
.parentViewController
เลิกใช้งานแล้ว.presentingViewController
ต้องใช้แทน
ใน iOS5 + ดังที่คุณเห็นในUIViewController Class Referenceคุณสามารถรับได้จากคุณสมบัติ "presentationViewController"
PresentationViewController ตัวควบคุมมุมมองที่นำเสนอตัวควบคุมมุมมองนี้ (อ่านเท่านั้น)
@property (nonatomic อ่านอย่างเดียว) UIViewController * presentationViewController
Discussion
ถ้าตัวควบคุมมุมมองที่ได้รับข้อความนี้แสดงโดยตัวควบคุมมุมมองอื่นคุณสมบัตินี้จะเก็บตัวควบคุมมุมมองที่กำลังนำเสนอ หากไม่มีการนำเสนอตัวควบคุมมุมมอง แต่มีการนำเสนอบรรพบุรุษตัวใดตัวหนึ่งคุณสมบัตินี้จะถือตัวควบคุมมุมมองที่นำเสนอบรรพบุรุษที่ใกล้ที่สุด หากไม่มีการนำเสนอตัวควบคุมมุมมองหรือบรรพบุรุษใด ๆ คุณสมบัตินี้ถือเป็นศูนย์
ความพร้อม
ใช้งานมีให้ใน iOS 5.0 และใหม่กว่า
ประกาศใน
UIViewController.h
presentingViewController
. นอกจากนี้ยังทำงานในตัวควบคุมมุมมองคอนเทนเนอร์ด้วยเนื่องจากจะข้ามผ่านบรรพบุรุษโดยอัตโนมัติ
หากไม่มีคุณสามารถกำหนดคุณสมบัติสำหรับสิ่งนี้ ( presentedAsModal
) ในคลาสย่อย UIViewController ของคุณและตั้งค่าเป็นYES
ก่อนนำเสนอ ViewController เป็นมุมมองโมดอล
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
คุณสามารถตรวจสอบค่านี้ได้ในการviewWillAppear
แทนที่ของคุณ
ฉันเชื่อว่าไม่มีคุณสมบัติอย่างเป็นทางการที่ระบุวิธีการนำเสนอมุมมอง แต่ไม่มีสิ่งใดป้องกันไม่ให้คุณสร้างของคุณเอง
UINavigationController
เป็นโมดอล ... เว้นแต่คุณจะสร้างตัวควบคุมการนำทางแบบกำหนดเองเพียงเพื่อเพิ่มคุณสมบัตินี้ และหลังจากนั้นภายในคอนโทรลเลอร์คุณจะต้องแคสต์ไปself.navigationController
ยังคลาสที่กำหนดเองนี้ทุกครั้งที่คุณต้องตรวจสอบว่าคอนโทรลเลอร์ถูกนำเสนอเป็นโมดอลหรือไม่
คำตอบของ Petronella ใช้ไม่ได้หากมีการนำเสนอ self.navigationController แต่ self ไม่เท่ากับ self.navigationController.viewControllers [0] ในกรณีนั้นด้วยตนเองจะถูกผลัก
นี่คือวิธีที่คุณสามารถแก้ไขปัญหาได้
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
และใน Swift:
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
|| self.tabBarController?.presentingViewController is UITabBarController
สิ่งนี้ควรใช้งานได้
if(self.parentViewController.modalViewController == self)…
UINavigationController
และUITabBarController
กรณี ตอนนี้ใช้งานได้ดี
วิธีที่ดีที่สุดในการตรวจสอบ
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
หากคุณไม่จำเป็นต้องแยกความแตกต่างระหว่างมุมมองโมดอลแบบเต็มหน้าจอและมุมมองที่ไม่ใช่โมดอลซึ่งเป็นกรณีในโครงการของฉัน (ฉันกำลังจัดการกับปัญหาที่เกิดขึ้นกับแผ่นฟอร์มและแผ่นหน้าเท่านั้น) คุณสามารถใช้ modalPresentationStyle คุณสมบัติของ UIViewController:
switch (self.modalPresentationStyle) {
case 0: NSLog(@"full screen, or not modal"); break;
case 1: NSLog(@"page sheet"); break;
case 2: NSLog(@"form sheet"); break;
}
ในSwift :
func isUIViewControllerPresentedAsModal() -> Bool {
if((self.presentingViewController) != nil) {
return true
}
if(self.presentingViewController?.presentedViewController == self) {
return true
}
if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
return true
}
if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
return true
}
return false
}
ในโปรเจ็กต์ของฉันฉันมีตัวควบคุมมุมมอง (รายละเอียด) ที่สามารถนำเสนอได้ทั้งแบบโมดูล (เมื่อเพิ่มรายการใหม่) หรือด้วยการกด (เมื่อแก้ไขรายการที่มีอยู่) โดยตัวควบคุมมุมมองหลัก เมื่อผู้ใช้แตะ [เสร็จสิ้น] ตัวควบคุมมุมมองรายละเอียดจะเรียกใช้เมธอดของ Master view controller เพื่อแจ้งว่าพร้อมที่จะปิด อาจารย์ต้องกำหนดว่าจะนำเสนอ Detail อย่างไรจึงจะรู้ว่าจะปิดอย่างไร นี่คือวิธีที่ฉันทำ:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
การแฮ็กเช่นนี้อาจใช้ได้ผล
UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
child = parent;
parent = child.parentViewController;
}
if (parent) {
// A view controller in the hierarchy was presented as a modal view controller
}
อย่างไรก็ตามฉันคิดว่าคำตอบก่อนหน้านี้เป็นวิธีที่สะอาดกว่า
สิ่งที่ได้ผลสำหรับฉันมีดังต่อไปนี้:
// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;
// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);
// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];
// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);
เท่าที่ฉันทดสอบมันใช้ได้กับ iOS7 และ iOS8 ไม่ได้ลองใช้ iOS6 อย่างไรก็ตาม
ฉันได้ตรวจสอบเพื่อหาคำตอบที่ถูกต้องสำหรับคำถามนี้และฉันไม่พบสิ่งใดที่ครอบคลุมสถานการณ์ที่เป็นไปได้ทั้งหมด ฉันเขียนโค้ดสองสามบรรทัดเหล่านี้ซึ่งดูเหมือนจะได้ผล คุณสามารถดูความคิดเห็นแบบอินไลน์เพื่อดูว่ามีการตรวจสอบอะไรบ้าง
- (BOOL)isModal {
BOOL modal = NO;
if ([self presentingViewController]) { //Some view Controller is presenting the current stack
UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
}
else {
modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
}
}
return modal;
}
หวังว่าจะช่วยได้
นี่คือ @ GabrielePetronella's เวอร์ชันแก้ไขของฉันisModal
ซึ่งทำงานร่วมกับตัวควบคุมมุมมองที่มีอยู่ซึ่งจะเดินตามลำดับชั้น parentViewController ก่อน ยังดึงโค้ดออกเป็นหลายบรรทัดเพื่อให้ชัดเจนว่ากำลังทำอะไร
var isModal: Bool {
// If we are a child view controller, we need to check our parent's presentation
// rather than our own. So walk up the chain until we don't see any parentViewControllers
var potentiallyPresentedViewController : UIViewController = self
while (potentiallyPresentedViewController.parentViewController != nil) {
potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
}
if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController {
return true
}
if let navigationController = potentiallyPresentedViewController.navigationController {
if navigationController.presentingViewController?.presentedViewController == navigationController {
return true
}
}
return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}