简体   繁体   中英

How do I get a UINavigationController to NOT change its view size when setting the translucent property?

I have an app where up until now I've been using a UINavigationController with a UINavigationBar that has its property translucent = YES. This means the UINavigationController's content view (ie the views from the view controllers you push) to be full-screen (minus status bar).

However, if you set the navigationBar.translucent = NO, this container view becomes 44pt shorter, as I suppose Apple has assumed you don't need any content under an opaque navigationBar.

... except if you're doing what we're doing and are employing a navigationBar that scrolls away (see This Post on how to do that ) So I'd like to know if this is possible.

I want to have translucent = NO, but have everything behave as if it were still set to YES. I like the functionality of the translucent = YES, but I don't actually want the bar to be made translucent by UIKit.

What worked for me was to add extendedLayoutIncludesOpaqueBars = true in viewDidLoad

something like this

override func viewDidLoad() {
   super.viewDidLoad()
   extendedLayoutIncludesOpaqueBars = true
}

Hope it will work for you as well

It's not necessarily a good answer but you could just offset your view that high if you're not translucent.

//This won't take into account orientation and probably other details
if(!self.navigationController.navigationBar.isTranslucent)
{
    self.view.frame = CGRectMake(0,0,-44,self.view.bounds.size.height);
}

You could put that in your viewDidLoad or viewWillAppear and if you have a bunch of view controllers you can just subclass them all and put your logic in the subclass.

I found a solution that works, although it is indeed a bit of a hack.

The idea is to give the translucent nav bar an opaque backing. Unfortunately I'm not happy with the solution in that it's dirty and not encapsulated and introduces some potential issues, but i AM happy because it got the job done.

In my Application's base view controller class (ie MyViewController : UIViewController), in the viewDidLoad method, I instantiate a new ivar UIView *_navigationBarBG and give it the same frame as self.navigationController.navigationBar. I then set it's backgroundColor property to [UIColor whiteColor] although this is how you achieve some more tint I guess. [EDIT:If you wanted to be a purist (color values remaining exactly as they come from the .psd), you could make the _navigationBarBG a UIImageView and use your custom background there, and the background of the actual UINavigationBar you set to draw clear (or stretch a 1px transparent image if you wanted to use a typical 'change your navigation bar using an image' recipe that's somewhere on the internet)]

if(self.navigationController)
{
    _navigationBarBG = [[UIView alloc] initWithFrame: self.navigationController.navigationBar.frame];
    _navigationBarBG.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:_navigationBarBG];
}

THEN, (and this is the crappy part, but I don't see any other way), I add this view as a subview. BUT, whenever you would normally make a call to [self.view addSubview: anyView], you have to make sure you call [self.view insertSubview: anyView belowSubview: _navigationBarBG];

if (_navigationBarBG)
    [self.view insertSubview: anyView belowSubview:_navigationBarBG];
else
    [self.view addSubview: anyView];

If you forget that, these added views will slide under your navbar background and look weird. So you need to know that this is a source of error.

WHY AM I DOING THIS? Again you might ask... I want to be able to have a scrolling navigation bar that scrolls out of the way when you scroll down your table view, thereby giving the user more screen space. This is done by using the scrollView delegate (scrollViewDidScroll:) and also viewWillAppear:

    // FIRST DEAL WITH SCROLLING NAVIGATION BAR
CALayer *layer = self.navigationController.navigationBar.layer;

CGFloat contentOffsetY = scrollView.contentOffset.y;
CGPoint newPosition;


if (contentOffsetY > _scrollViewContentOffsetYThreshold && self.scrollingNavigationBarEnabled) {
    newPosition = CGPointMake(layer.position.x,
                                 22 - MIN((contentOffsetY - _scrollViewContentOffsetYThreshold), 48.0));  // my nav bar BG image is 48.0 tall
    layer.position = newPosition;
    [_navigationBarBG setCenter: newPosition];  // if it's nil, nothing happens
}
else
{
    newPosition = kNavBarDefaultPosition;  // i.e. CGPointMake(160, 22) -- portrait only
    layer.position = newPosition;
    [_navigationBarBG setCenter: newPosition]; // if it's nil, nothing happens
}

I was looking for an answer to this as I wanted my subviews to be at (0,0) and not (0,44)(in reference to the Screen bounds), but I could not find an answer on how to set this in the NavigationController, which I thought would be an included property.

What I ended up doing that was very simple is adding a subview to the navigation controller that was the width and height of the Navigation Bar, but then insert the subview below the Navigation Bar.

Now the setting is Translucent = YES, but it still appears solid and the subviews behave how I want.

EDIT: After re-reading your original post, I suppose if you're going to be rolling the nav bar away, you'll have to take into account hiding and showing the new subview as you do the same with the nav bar

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM