私のView Controllerコードでは、どうすれば区別できますか?
presentingViewController
とisMovingToParentViewController
は両方ともYES
であるため、あまり役に立ちません。
物事を複雑にしているのは、親View Controllerがモーダルであることがあり、その上にチェック対象のView Controllerがプッシュされることです。
私の問題は、HtmlViewController
をUINavigationController
に埋め込んでから表示することです。それが、私自身の試みと以下の良い答えがうまくいかなかった理由です。
HtmlViewController* termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;
modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
animated:YES
completion:nil];
モーダルであるかどうかを判断するのではなく、View Controllerに伝えた方が良いと思います。
塩の粒で取り、テストしませんでした。
- (BOOL)isModal {
if([self presentingViewController])
return YES;
if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
return YES;
if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
return YES;
return NO;
}
1つのメソッドを見落としていました:isBeingPresented
。
isBeingPresented
は、View Controllerが表示されている場合はtrue、プッシュされている場合はfalseです。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if ([self isBeingPresented]) {
// being presented
} else if ([self isMovingToParentViewController]) {
// being pushed
} else {
// simply showing again because another VC was dismissed
}
}
In Swift:
// MARK: - UIViewController implementation
extension UIViewController {
var isModal: Bool {
let presentingIsModal = presentingViewController != nil
let presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController
let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController
return presentingIsModal || presentingIsNavigation || presentingIsTabBar
}
}
self.navigationController!= nilは、ナビゲーションスタック内にあることを意味します。
ナビゲーションコントローラーがモーダルモードで表示されているときに現在のビューコントローラーがプッシュされる場合を処理するために、現在のビューコントローラーがナビゲーションスタックのルートコントローラーであるかどうかを確認するコードをいくつか追加しました。
extension UIViewController{
func isModal() -> Bool {
if let navigationController = self.navigationController{
if navigationController.viewControllers.first != self{
return false
}
}
if self.presentingViewController != nil {
return true
}
if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController {
return true
}
if self.tabBarController?.presentingViewController is UITabBarController {
return true
}
return false
}
}
Swift
プッシュされたtrue
が提示されたUIViewController
スタックにある場合、isModal()
がUINavigationController
を返すときに、以前の回答で言及された問題に対処するソリューションがあります。
extension UIViewController {
var isModal: Bool {
if let index = navigationController?.viewControllers.index(of: self), index > 0 {
return false
} else if presentingViewController != nil {
return true
} else if navigationController?.presentingViewController?.presentedViewController == navigationController {
return true
} else if tabBarController?.presentingViewController is UITabBarController {
return true
} else {
return false
}
}
}
これは今のところうまくいきます。最適化する場合は、共有してください。
Swift 4
var isModal: Bool {
return presentingViewController != nil ||
navigationController?.presentingViewController?.presentedViewController === navigationController ||
tabBarController?.presentingViewController is UITabBarController
}
ここで多くの人が示唆しているように、「チェック」メソッドはすべての場合にうまく機能しないと考えています。私のプロジェクトでは、それを手動で管理するソリューションを考え出しました。ポイントは、私たちは通常、自分でプレゼンテーションを管理します-これは舞台裏で起こることではなく、内省する必要があります。
DEViewController.h
ファイル:
#import <UIKit/UIKit.h>
// it is a base class for all view controllers within a project
@interface DEViewController : UIViewController
// specify a way viewcontroller, is presented by another viewcontroller
// the presented view controller should manually assign the value to it
typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) {
SSViewControllerPresentationMethodUnspecified = 0,
SSViewControllerPresentationMethodPush,
SSViewControllerPresentationMethodModal,
};
@property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod;
// other properties/methods...
@end
プレゼンテーションは次の方法で管理できます。
ナビゲーションスタックにプッシュ:
// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];
ナビゲーションでモーダルに表示:
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];
モーダル表示:
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];
また、DEViewController
では、前述のプロパティがSSViewControllerPresentationMethodUnspecified
と等しい場合、「checking」にフォールバックを追加できます。
- (BOOL)isViewControllerPushed
{
if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
}
else {
// fallback to default determination method
return (BOOL)self.navigationController.viewControllers.count > 1;
}
}
モーダルで表示するすべてのviewControllerが新しいnavigationController内にラップされていると仮定すると(これは常に実行する必要があります)、VCにこのプロパティを追加できます。
private var wasPushed: Bool {
guard let vc = navigationController?.viewControllers.first where vc == self else {
return true
}
return false
}
コントローラーがプッシュされたことを検出するには、または必要な場所で以下のコードを使用するだけではありません。
if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {
// Not pushed
}
else {
// Pushed
}
このコードが誰にも役立つことを願っています...
self.navigationController != nil
は、ナビゲーションスタック内にあることを意味します。
if navigationController.presentingViewController != nil {
// Navigation controller is being presented modally
}
IOS 5.0以降を使用している場合は、このコードを使用してください
-(BOOL)isPresented
{
if ([self isBeingPresented]) {
// being presented
return YES;
} else if ([self isMovingToParentViewController]) {
// being pushed
return NO;
} else {
// simply showing again because another VC was dismissed
return NO;
}
}
if let navigationController = self.navigationController, navigationController.isBeingPresented {
// being presented
}else{
// being pushed
}