Instantly share code, notes, and snippets.
Created
September 20, 2017 14:16
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save colinhumber/b1ed339f28a5854cf0005841090176c8 to your computer and use it in GitHub Desktop.
Hacky way to get a custom nav bar height
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "SBBaseNavigationBar.h" | |
@interface SBBaseNavigationBar (iOS11HacksPrivate) | |
@property (nullable, nonatomic, readonly) UIView *navigationBarContentView; | |
@end | |
@implementation SBBaseNavigationBar | |
@dynamic promptViewHeight; | |
#pragma mark - Initialization | |
- (instancetype)initWithNavigationBarHeight:(CGFloat)height { | |
self = [super initWithFrame:CGRectZero]; | |
if (self) { | |
[self sb_navigationBarCommonInitWithNavigationBarHeight:height]; | |
} | |
return self; | |
} | |
- (instancetype)initWithFrame:(CGRect)frame { | |
return [self initWithNavigationBarHeight:60.0]; | |
} | |
- (instancetype)initWithCoder:(NSCoder *)aDecoder { | |
self = [super initWithCoder:aDecoder]; | |
if (self) { | |
[self sb_navigationBarCommonInitWithNavigationBarHeight:60.0]; | |
} | |
return self; | |
} | |
- (void)sb_navigationBarCommonInitWithNavigationBarHeight:(CGFloat)height { | |
// enforce minimum height | |
if (height < SBBaseNavigationBar.minimumBarHeight) { | |
height = SBBaseNavigationBar.minimumBarHeight; | |
} | |
// defaults | |
_navigationBarHeight = height; | |
} | |
#pragma mark - Setters | |
- (void)setNavigationBarHeight:(CGFloat)navigationBarHeight { | |
if (navigationBarHeight < SBBaseNavigationBar.minimumBarHeight) { | |
navigationBarHeight = SBBaseNavigationBar.minimumBarHeight; | |
} | |
_navigationBarHeight = navigationBarHeight; | |
[self setNeedsLayout]; | |
} | |
#pragma mark - Getters | |
+ (CGFloat)minimumBarHeight { | |
return 44.0; | |
} | |
#pragma mark - Layout | |
- (void)setBounds:(CGRect)bounds { | |
bounds.size.height = self.navigationBarHeight; | |
[super setBounds:bounds]; | |
} | |
- (void)setFrame:(CGRect)frame { | |
//when nav is pushed modally, the navigationbar height isn't correct for the onscreen | |
//animation, and only takes the correct height once the animation is correct | |
//this forces the frame to adhere to the set navigationBarHeight for all instances | |
frame.size.height = self.navigationBarHeight; | |
// if we're adjusting the nav bar's layout to take the status bar into account, ensure the nav bar's origin.y is always at the bottom of the status bar. | |
// Works around an issue when presenting a full screen modal on compact where the nav bar's height is set correctly, but the | |
// origin is at 0 | |
if (@available(iOS 11.0, *)) { | |
if (self.adjustsLayoutForStatusBar) { | |
frame.origin.y = CGRectGetHeight(UIApplication.extensionSafeSharedApplication.statusBarFrame); | |
} | |
} | |
[super setFrame:frame]; | |
} | |
- (void)setCenter:(CGPoint)center { | |
if (@available(iOS 11.0, *)) { | |
center.y = (self.navigationBarHeight / 2) + self.centerOffset; | |
} | |
[super setCenter:center]; | |
} | |
- (void)layoutSubviews { | |
[super layoutSubviews]; | |
UIView *backgroundView = self.subviews.firstObject; | |
CGRect backgroundFrame = backgroundView.frame; | |
if (@available(iOS 11.0, *)) { | |
backgroundFrame.size.height = self.navigationBarHeight - CGRectGetMinY(backgroundFrame); | |
backgroundView.frame = backgroundFrame; | |
[self overrideNavigationContentViewLayout]; | |
} | |
} | |
- (CGSize)sizeThatFits:(CGSize)size { | |
CGSize aSize = [super sizeThatFits:size]; | |
aSize.height = self.navigationBarHeight; | |
return aSize; | |
} | |
@end | |
@implementation SBBaseNavigationBar (iOS11Hacks) | |
- (void)overrideNavigationContentViewLayout { | |
[self.navigationBarContentView.layer removeAnimationForKey:@"position"]; | |
CGFloat statusBarInset = CGRectGetHeight(UIApplication.sharedApplication.statusBarFrame); | |
CGFloat contentViewOriginY = ((self.navigationBarHeight - SBBaseNavigationBar.minimumBarHeight - statusBarInset) / 2); | |
CGRect contentViewFrame = self.navigationBarContentView.frame; | |
contentViewFrame.origin.y = contentViewOriginY; | |
self.navigationBarContentView.frame = contentViewFrame; | |
} | |
@end | |
@implementation SBBaseNavigationBar (iOS11HacksPrivate) | |
- (UIView *)navigationBarContentView { | |
UIView *contentView = [self.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *evaluatedObject, NSDictionary<NSString *,id> *bindings) { | |
return [evaluatedObject isKindOfClass:NSClassFromString(@"_UINavigationBarContentView")]; | |
}]].firstObject; | |
return contentView; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment