From 2cb634bb0b564a5e4ddadd259df560a53c91e455 Mon Sep 17 00:00:00 2001 From: Mr Speaker Date: Thu, 16 Jul 2015 04:18:12 -0700 Subject: [PATCH] Nav ios hide hairline Summary: For the current project I am working on I needed to add a boolean option (`shadowHidden`) to remove the 1px hairline shadow from the NavigationIOS component: `` By default, or with `shadowHidden={false}` it looks like this: ![withhairline](https://cloud.githubusercontent.com/assets/129330/8145401/d2704956-11d4-11e5-86e8-a75435b68480.png) Setting the shadow hidden with `shadowHidden={true}` looks like this: ![nohairline2](https://cloud.githubusercontent.com/assets/129330/8145405/148ed56e-11d5-11e5-85d6-f8cd3453d5ac.png) The code it uses to do the actual hiding is... a bit of a hack (*I* think), but it's the only way currently to do it, and is the way they do it in the iPhone calendar app: iterating through the subviews and removing the shadow image. This removes the shadow *and* keeps the translucent blurry effect with a ScrollView (see this [SO discussion](http://stackoverflow.com/questions/18160173/how-to-remove-uinavigationbar-inner Closes https://github.com/facebook/react-native/pull/1615 Github Author: Mr Speaker --- .../Components/Navigation/NavigatorIOS.ios.js | 7 ++++ React/Views/RCTNavItem.h | 1 + React/Views/RCTNavItemManager.m | 1 + React/Views/RCTWrapperViewController.m | 33 +++++++++++++------ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js index 053ab0ee38..5d47b4df6e 100644 --- a/Libraries/Components/Navigation/NavigatorIOS.ios.js +++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js @@ -60,6 +60,7 @@ var RCTNavigatorItem = createReactNativeComponentClass({ tintColor: true, translucent: true, navigationBarHidden: true, + shadowHidden: true, titleTextColor: true, style: true, }, @@ -281,6 +282,11 @@ var NavigatorIOS = React.createClass({ */ navigationBarHidden: PropTypes.bool, + /** + * A Boolean value that indicates whether to hide the 1px hairline shadow + */ + shadowHidden: PropTypes.bool, + /** * The default wrapper style for components in the navigator. * A common use case is to set the backgroundColor for every page @@ -640,6 +646,7 @@ var NavigatorIOS = React.createClass({ rightButtonTitle={route.rightButtonTitle} onNavRightButtonTap={route.onRightButtonPress} navigationBarHidden={this.props.navigationBarHidden} + shadowHidden={this.props.shadowHidden} tintColor={this.props.tintColor} barTintColor={this.props.barTintColor} translucent={this.props.translucent !== false} diff --git a/React/Views/RCTNavItem.h b/React/Views/RCTNavItem.h index 16c1e7f5db..9b75673c30 100644 --- a/React/Views/RCTNavItem.h +++ b/React/Views/RCTNavItem.h @@ -19,6 +19,7 @@ @property (nonatomic, strong) UIImage *backButtonIcon; @property (nonatomic, copy) NSString *backButtonTitle; @property (nonatomic, assign) BOOL navigationBarHidden; +@property (nonatomic, assign) BOOL shadowHidden; @property (nonatomic, strong) UIColor *tintColor; @property (nonatomic, strong) UIColor *barTintColor; @property (nonatomic, strong) UIColor *titleTextColor; diff --git a/React/Views/RCTNavItemManager.m b/React/Views/RCTNavItemManager.m index dab6ee049a..8350af2e90 100644 --- a/React/Views/RCTNavItemManager.m +++ b/React/Views/RCTNavItemManager.m @@ -22,6 +22,7 @@ RCT_EXPORT_MODULE() } RCT_EXPORT_VIEW_PROPERTY(navigationBarHidden, BOOL) +RCT_EXPORT_VIEW_PROPERTY(shadowHidden, BOOL) RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL) diff --git a/React/Views/RCTWrapperViewController.m b/React/Views/RCTWrapperViewController.m index c1893353b1..b9fd8ec3d7 100644 --- a/React/Views/RCTWrapperViewController.m +++ b/React/Views/RCTWrapperViewController.m @@ -63,6 +63,20 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder) _currentBottomLayoutGuide = self.bottomLayoutGuide; } +static UIView *RCTFindNavBarShadowViewInView(UIView *view) +{ + if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1) { + return view; + } + for (UIView *subview in view.subviews) { + UIView *shadowView = RCTFindNavBarShadowViewInView(subview); + if (shadowView) { + return shadowView; + } + } + return nil; +} + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; @@ -71,20 +85,18 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder) if ([self.parentViewController isKindOfClass:[UINavigationController class]]) { [self.navigationController - setNavigationBarHidden:_navItem.navigationBarHidden - animated:animated]; - - if (!_navItem) { - return; - } + setNavigationBarHidden:_navItem.navigationBarHidden + animated:animated]; UINavigationBar *bar = self.navigationController.navigationBar; bar.barTintColor = _navItem.barTintColor; bar.tintColor = _navItem.tintColor; bar.translucent = _navItem.translucent; - if (_navItem.titleTextColor) { - [bar setTitleTextAttributes:@{NSForegroundColorAttributeName : _navItem.titleTextColor}]; - } + bar.titleTextAttributes = _navItem.titleTextColor ? @{ + NSForegroundColorAttributeName: _navItem.titleTextColor + } : nil; + + RCTFindNavBarShadowViewInView(bar).hidden = _navItem.shadowHidden; UINavigationItem *item = self.navigationItem; item.title = _navItem.title; @@ -129,7 +141,8 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder) // finishes, be it a swipe to go back or a standard tap on the back button [super didMoveToParentViewController:parent]; if (parent == nil || [parent isKindOfClass:[UINavigationController class]]) { - [self.navigationListener wrapperViewController:self didMoveToNavigationController:(UINavigationController *)parent]; + [self.navigationListener wrapperViewController:self + didMoveToNavigationController:(UINavigationController *)parent]; } }