Cocoa touch UINavigationController:将公共填充/边距应用于所有弹出的视图控制器';s的观点

Cocoa touch UINavigationController:将公共填充/边距应用于所有弹出的视图控制器';s的观点,cocoa-touch,ios,uikit,uinavigationcontroller,Cocoa Touch,Ios,Uikit,Uinavigationcontroller,我有一个UINavigationController,我希望弹出到堆栈上的每个视图控制器的视图都有一个公共的填充/边距(例如,所有边上都有25个像素)。实现这一目标的最佳方式是什么 我最初认为我可以实现UINavigationControllerDelegate和navigationController:didShowViewController:animated或navigationController:willShowViewController:animated方法,只需更改即将显示的视图

我有一个
UINavigationController
,我希望弹出到堆栈上的每个视图控制器的视图都有一个公共的填充/边距(例如,所有边上都有25个像素)。实现这一目标的最佳方式是什么

我最初认为我可以实现
UINavigationControllerDelegate
navigationController:didShowViewController:animated
navigationController:willShowViewController:animated
方法,只需更改即将显示的视图控制器的框架即可。但这似乎没有效果

我尝试在视图控制器的
viewdideappeage
viewwillappeage
方法中执行相同的操作,但这也不起作用。理想情况下,我不想在控制器中添加任何逻辑,因为它们可能并不总是在导航控制器中使用

我还没有尝试的最后一个想法是创建一个“包装器”
UIViewController
,它实际上会被推到这个堆栈上。这个包装器将实际视图控制器的视图添加为一个子视图,并带有一个提供所需边距的框架。这里的缺点是,我需要子类化
UINavigationController
并覆盖
pushViewController:animated
,在这里将初始化和推送包装器。苹果的文档表明,
UINavigationController
并不意味着要被子类化


提前感谢。

我解决了这个问题,在
UIViewController
视图
周围放置了一个“包装器”
UIViewController
,而不是
UIViewController
本身。然后,包装器视图通过在
layoutSubviews
方法中设置子视图的框架来填充子视图

为了方便起见,我附上了我使用的代码。要使用,请将
UINavigationController
替换为
PaddedNavigationController
,并设置
PaddedNavigationController
insets
属性

PaddedNavigationController.h

#import <Foundation/Foundation.h>

@interface PaddedNavigationController : UINavigationController
{
    UIEdgeInsets _insets;
}

@property (nonatomic, assign) UIEdgeInsets insets;

@end

试图实现上述“最后一个想法”,但遇到了障碍。由于正在显示的视图控制器实际上是由另一个视图控制器“包装”的,并且包装器实际上被推到堆栈上,因此正在显示的视图控制器上的
navigationController
属性是
nil
。这意味着我无法获得导航控制器的控制柄,以便将另一个视图控制器推到顶部。另一个数据点:在
navigationController:didShowViewController:animated
中更改视图控制器的视图帧实际上起作用,但是视图控制器首先出现在原始帧中,然后在事实发生后调整大小,这看起来很糟糕。不过,在
navigationController:willShowViewController:animated
中更改帧没有任何效果。我还没有机会尝试一下,但我接受了它,因为它看起来是一个非常好的解决方案(至少比我能想到的任何解决方案都好)。谢谢沿着这条路走下去之后,结果发现这实际上并没有起到很好的作用。您的视图控制器确实不能不知道它们的视图是否已包装。尝试添加子视图并使用视图控制器的视图边界来确定子视图的边界将导致不期望的结果。此外,当出现内存警告并且视图控制器的视图被重新加载时,这种方法会出现问题,而不会被包装在
PaddedView
实例中。
#import "PaddedNavigationController.h"

@interface PaddedView : UIView
{
    UIView *_view;
    UIEdgeInsets _insets;
}

@property (nonatomic, assign) UIEdgeInsets insets;

+ (PaddedView *) wrapView:(UIView *)view withInsets:(UIEdgeInsets)insets;
- (id) initWithView:(UIView *)view insets:(UIEdgeInsets)insets;

@end


@implementation PaddedNavigationController

@synthesize insets = _insets;

- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    //check if the UIViewController's view has already been wrapped by the PaddedView; don't want to wrap it twice
    if(![viewController.view isKindOfClass:[PaddedView class]])
    {
        viewController.view = [PaddedView wrapView:viewController.view withInsets:self.insets];
    }
    [super pushViewController:viewController animated:animated];
}

- (void) setInsets:(UIEdgeInsets)insets
{
    _insets = insets;

    //loop through this navigation controller's view controllers and set the new insets on any PaddedViews
    for(UIViewController *viewController in self.viewControllers)
    {
        if([viewController.view isKindOfClass:[PaddedView class]])
        {
            PaddedView *padded = (PaddedView *)viewController.view;
            padded.insets = insets;
        }
    }
}

@end


@implementation PaddedView

@synthesize insets = _insets;

+ (PaddedView *) wrapView:(UIView *)view withInsets:(UIEdgeInsets)insets
{
    return [[[PaddedView alloc] initWithView:view insets:insets] autorelease];
}

- (id) initWithView:(UIView *)view insets:(UIEdgeInsets)insets
{
    if(self = [super initWithFrame:view.frame])
    {
        _insets = insets;
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _view = [view retain];
        [self addSubview:view];
    }
    return self;
}

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

- (void) layoutSubviews
{
    //apply the insets to the subview
    _view.frame = CGRectMake(self.insets.left, self.insets.top, self.frame.size.width - self.insets.left - self.insets.right, self.frame.size.height - self.insets.top - self.insets.bottom);
}

- (void) setInsets:(UIEdgeInsets)insets
{
    _insets = insets;
    //we need to re-layout the subviews as the insets have changed
    [self layoutSubviews];
}

@end