实现 UINavigationControllerDelegate 时出现问题

发布于 2024-10-19 18:52:21 字数 1638 浏览 3 评论 0原文

我可能对 UINavigationControllerDelegate 协议的使用有一些误解。这是我的情况:

我有一个 ViewController,我们称之为 BViewController,它可以显示 PopoverViewController。 BViewController 是 NavigationContoller 堆栈中的第二个 ViewController,仅次于 AViewController。当用户点击 BViewController 中的按钮时,我需要关闭 PopoverViewController,并且应用程序将我们带回之前的视图 - AViewController。

为此,我在 BViewController 中实现了以下内容

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"BViewController will disappear");
    // Check whether the popoverViewController is visible
    if (self.popoverController.popoverVisible==YES) {
        [self.popoverController dismissPopoverAnimated:NO];
    }
}

,但是,框架不会直接调用它,因为 BViewController 位于 NavigationController 内部。因此,我使用我的 NavigationController 注册了一个 UINavigationControllerDelegate 并实现了以下两个方法:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // Pass the message on to the viewController in question
    [viewController viewWillAppear:animated];
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // Pass the message on to the viewController in question
    [viewController viewWillDisappear:animated];
}

但是,这两个方法中传入的 viewController 参数似乎就是即将显示的参数。我本以为第二种方法可以让我访问即将消失的方法。因此,当用户点击上述按钮时,viewWillDisappear 会在 AViewController(即将显示)上调用,而不是在 BViewController(即将消失)上调用。听起来对吗?苹果文档在这两种情况下都提到

正在显示其视图和导航项属性的视图控制器。

……我认为这还不太清楚。谢谢你们的帮助,伙计们。

I may have some misunderstanding regarding the use of the UINavigationControllerDelegate protocol. Here is my situation:

I have a ViewController, let's call it, BViewController that may display a PopoverViewController. BViewController is the second ViewController in a NavigationContoller's stack, after AViewController. I need to dismiss the PopoverViewController when the user hits a button in BViewController and the app takes us back to the previous view--AViewController.

To do that, I have implemented the following in BViewController

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"BViewController will disappear");
    // Check whether the popoverViewController is visible
    if (self.popoverController.popoverVisible==YES) {
        [self.popoverController dismissPopoverAnimated:NO];
    }
}

However, that is not being called directly by the framework as BViewController is inside a NavigationController. Hence, I register a UINavigationControllerDelegate with my NavigationController and implement the following two methods:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // Pass the message on to the viewController in question
    [viewController viewWillAppear:animated];
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // Pass the message on to the viewController in question
    [viewController viewWillDisappear:animated];
}

However, it seems that the passed in viewController parameter in both methods is the one that is about to be shown. I would have expected that the second method gives me access to the one that is about to disappear. So, when the user hits aforementioned button viewWillDisappear gets called on AViewController (which is about to be shown) and not on BViewController (which is about to disappear). Does that sound right? The apple documentation refers in both cases to

The view controller whose view and navigation item properties are being shown.

...which is not quite clear, I think. Thank you for some help, guys.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜司空 2024-10-26 18:52:21

两个委托方法都被调用以执行相同的操作(显示视图控制器)。 新视图控制器在 GUI 中可见之前调用 navigationController: willShowViewController:animated:navigationController:navigationController didShowViewController:animated: 在新视图控制器显示后被调用。

您会在苹果的许多委托协议中找到这种模式。不幸的是,您在 NavigationViewController 中没有委托方法来告诉您该操作是弹出还是推送。

The two delegate method are both called for the same action (showing a view controller). The navigationController: willShowViewController:animated: is called before the new view controller is visible in the gui. The navigationController:navigationController didShowViewController:animated: is called after the new view controller is shown.

You will find this pattern in a lot of delegate protocols from apple. Unfortunately you do not have a delegate method in the NavigationViewController which tells you if the action was a pop or push.

生死何惧 2024-10-26 18:52:21

我挂钩我自己的协议,它将了解 TO 和 FROM 双方:

NavigationControllerDelegate.h:

@protocol NavigationControllerDelegate <NSObject>
@required
-(void) navigationController: (UINavigationController*) navController 
  willMoveFromViewController: (UIViewController*) from 
        toViewController: (UIViewController*) to;
@end

而不是常规的 UINavigationViewController,然后我使用一个小帮助程序类来跟踪视图控制器:

NavigationHandler.h:

@interface NavigationHandler : NSObject <UINavigationControllerDelegate> {
  NSMutableArray* m_viewControllers;
}

在我的应用程序委托中,我创建这些对象之一并将其设置为导航控制器的委托:

...
m_navigationHandler = [[NavigationHandler alloc] init];
navigationController = [[UINavigationController alloc] initWithRootViewController: mainMenuViewController];
navigationController.delegate = m_navigationHandler;
...

从那时起,这是一个将我自己的视图控制器列表与导航控制器所具有的列表进行比较的简单情况:

NavigationHandler.m

#import "NavigationHandler.h"
#import "NavigationControllerDelegate.h"

@implementation NavigationHandler

-(id) init {
  if ((self = [super init])) {
    m_viewControllers = [[NSMutableArray alloc] init];
  }
  return self;
}

-(void) dealloc {
  [m_viewControllers release];
  [super dealloc];
}

- (void)navigationController:(UINavigationController *)navController 
  willShowViewController:(UIViewController *)viewController 
                animated:(BOOL)animated {

  // Find out which viewControllers are disappearing and appearing

  UIViewController* appearingViewController = nil;
  UIViewController* disappearingViewController = nil;

  if ([m_viewControllers count] < [navController.viewControllers count]) {

    // pushing
    if ([m_viewControllers count] > 0) {
      disappearingViewController = [m_viewControllers lastObject];
    }
    appearingViewController = viewController;
    [m_viewControllers addObject: viewController];

  } else if ([m_viewControllers count] > [navController.viewControllers count]) {

    // popping
    disappearingViewController = [m_viewControllers lastObject];
    appearingViewController = viewController;
    [m_viewControllers removeLastObject];

  } else {
    return;
  }

  // Tell the view that will disappear
  if (disappearingViewController != nil) {
    if ([disappearingViewController conformsToProtocol: @protocol(NavigationControllerDelegate)]) {
      if ([disappearingViewController respondsToSelector: @selector(navigationController:willMoveFromViewController:toViewController:)]) {
        UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)disappearingViewController;
        [vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
      }
    }
  }

  // Tell the view that will appear
  if ([appearingViewController conformsToProtocol: @protocol(NavigationControllerDelegate)]) {
    if ([appearingViewController respondsToSelector:@selector(navigationController:willMoveFromViewController:toViewController:)]) {
      UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)appearingViewController;
      [vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
    }
  }
}   

@end

I hook in my own protocol, which will know about the TO and FROM sides:

NavigationControllerDelegate.h:

@protocol NavigationControllerDelegate <NSObject>
@required
-(void) navigationController: (UINavigationController*) navController 
  willMoveFromViewController: (UIViewController*) from 
        toViewController: (UIViewController*) to;
@end

Instead of the regular UINavigationViewController, I then use a little helper class which keeps track of the view controllers:

NavigationHandler.h:

@interface NavigationHandler : NSObject <UINavigationControllerDelegate> {
  NSMutableArray* m_viewControllers;
}

In my app delegate, I create one of these objects and set it as the delegate of the navigation controller:

...
m_navigationHandler = [[NavigationHandler alloc] init];
navigationController = [[UINavigationController alloc] initWithRootViewController: mainMenuViewController];
navigationController.delegate = m_navigationHandler;
...

And from then on its a simple case of comparing my own list of view controllers with what the navigation controller has:

NavigationHandler.m

#import "NavigationHandler.h"
#import "NavigationControllerDelegate.h"

@implementation NavigationHandler

-(id) init {
  if ((self = [super init])) {
    m_viewControllers = [[NSMutableArray alloc] init];
  }
  return self;
}

-(void) dealloc {
  [m_viewControllers release];
  [super dealloc];
}

- (void)navigationController:(UINavigationController *)navController 
  willShowViewController:(UIViewController *)viewController 
                animated:(BOOL)animated {

  // Find out which viewControllers are disappearing and appearing

  UIViewController* appearingViewController = nil;
  UIViewController* disappearingViewController = nil;

  if ([m_viewControllers count] < [navController.viewControllers count]) {

    // pushing
    if ([m_viewControllers count] > 0) {
      disappearingViewController = [m_viewControllers lastObject];
    }
    appearingViewController = viewController;
    [m_viewControllers addObject: viewController];

  } else if ([m_viewControllers count] > [navController.viewControllers count]) {

    // popping
    disappearingViewController = [m_viewControllers lastObject];
    appearingViewController = viewController;
    [m_viewControllers removeLastObject];

  } else {
    return;
  }

  // Tell the view that will disappear
  if (disappearingViewController != nil) {
    if ([disappearingViewController conformsToProtocol: @protocol(NavigationControllerDelegate)]) {
      if ([disappearingViewController respondsToSelector: @selector(navigationController:willMoveFromViewController:toViewController:)]) {
        UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)disappearingViewController;
        [vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
      }
    }
  }

  // Tell the view that will appear
  if ([appearingViewController conformsToProtocol: @protocol(NavigationControllerDelegate)]) {
    if ([appearingViewController respondsToSelector:@selector(navigationController:willMoveFromViewController:toViewController:)]) {
      UIViewController<NavigationControllerDelegate>* vcDelegate = (UIViewController<NavigationControllerDelegate>*)appearingViewController;
      [vcDelegate navigationController: navController willMoveFromViewController: disappearingViewController toViewController: appearingViewController];
    }
  }
}   

@end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文