我终于找到了解决方案。
我不得不用我的自定义子类重写UINavigation bar以改变高度。通过使用外观代理,标题和导航项目可以正确地重新定位。不幸的是,代理不能用于向后移动后退按钮的箭头(在iOS 7上),所以我们必须重写layoutSubview来处理该事件。
#define kAppNavBarHeight 66.0
@implementation TATallNavigationBar
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setupAppearance];
}
return self;
}
- (id)init
{
self = [super init];
if (self) {
[self setupAppearance];
}
return self;
}
- (void)setupAppearance {
static BOOL appearanceInitialised = NO;
if (!appearanceInitialised) {
// Update the appearance of this bar to shift the icons back up to their normal position
CGFloat offset = 44 - kAppNavBarHeight;
[[TATallNavigationBar appearance] setTitleVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackgroundVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackButtonBackgroundVerticalPositionAdjustment:offset forBarMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearanceWhenContainedIn:[RRSNavigationBar class], nil] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, offset) forBarMetrics:UIBarMetricsDefault];
appearanceInitialised = YES;
}
}
- (CGSize)sizeThatFits:(CGSize)size {
return CGSizeMake(self.superview.frame.size.width, kNavBarheight);
}
- (void)layoutSubviews {
static CGFloat yPosForArrow = -1;
[super layoutSubviews];
// There's no official way to reposition the back button's arrow under iOS 7. It doesn't shift with the title.
// We have to reposition it here instead.
for (UIView *view in self.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. We're not calling any private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:@"_UINavigationBarBackIndicatorView"]) {
CGRect frame = view.frame;
if (yPosForArrow < 0) {
// On the first layout we work out what the actual position should be by applying our offset to the default position.
yPosForArrow = frame.origin.y + (44 - kAppNavBarHeight);
}
// Update the frame.
frame.origin.y = yPosForArrow;
view.frame = frame;
}
}
}
@end
注意,很容易在XCode中可以指定子类:点击UINavigationController的,您可以访问到UINavigationBar的在左栏中。点击它并在检查器中更改它的子类。
我也创建了这个要点:
https://gist.github.com/timothyarmes/7080170
如何确定你是对_UINavigationBarBackIndicatorView使用是可以接受的?这是一个无证的财产,如果苹果改变它,你的应用程序可能会被打破。 – Tim
我只是在测试类的类型,所以从接受的角度来看应该没问题。它可能会在未来的操作系统更新中发生变化,但我不认为这会很快发生,所以我个人确定。如果你愿意的话,你总是可以尝试找到另一种方法来检查特定的视图(例如,我的代码的第一个版本,我看它的大小和位置)。 – tarmes
我遇到了另一个使用我自己版本的解决方案的问题,后来出现了问题,因为我推送了更多的视图控制器,我不需要这么高 - 关于如何将它变成更优雅的解决方案的任何想法? – Tim