UINavigationItem Prompt Issue

2019-02-13 14:29发布

问题:

I'm having a problem with the prompt on a UINavigationItem that I just can't resolve...

I have a master and a detail view controller. When I push from the master to the detail a prompt is shown on the detail view controller:

However, when I pop back to the master view controller, the view isn't resized and the window shows through (the window has been coloured red):

This only happens on iOS7, on iOS6 the view resizes as expected.

I've tried a few things such as setting the prompt to nil in viewWillDisappear or viewDidDisappear but nothing seems to fix it.

If I set the navigation bar in the navigation controller to translucent it does fix this - unfortunately that's not an option.

I've created a very small example project here which demonstrates the issue: https://github.com/InsertWittyName/NavigationItemPrompt

Thanks in advance for any help!

回答1:

A solution I can think of is to subclass the UIView of the master, and implement viewDidMoveToSuperview to set the frame of the view to be from the navigation bar's height to the end of the superview. Since the navigation bar is not translucent, your job is easier, as you don't have to take into account layout guides and content insets.

A few things to notice. When pushing and popping, the system moves your view controller's view into another superview for the animation and then returns it to the navigation controller's private view hierarchy. Also, when a view goes outside of the view hierarchy, the superview becomes nil.

Here is an example implementation:

@interface LNView : UIView

@end

@implementation LNView

- (void)viewDidMoveToSuperview
{
    [super viewDidMoveToSuperview];

    if(self.superview != nil)
    {
        CGRect rect = self.superview.bounds;

        rect.origin.y += 44;
        rect.size.height -= 44;

        [self setFrame:rect];
    }
}

@end

This is not a perfect implementation because it uses a hardcoded value for the navigation bar's height, does not take into account a possible toolbar, etc. But all these you can add as properties to this view and in viewDidLoad, before it starts going into the view hierarchy, set the parameters according to your needs.



回答2:

You can remove the prompt when the user taps the back button, like this

override func willMove(toParentViewController parent: UIViewController?) {
    super.willMove(toParentViewController: parent)
    if parent == nil {
        navigationItem.prompt = nil
    }
}


回答3:

You've given the answer yourself - brilliantly. It's a bug, but checking Translucent avoids the bug. Therefore the solution is to check Translucent and then compensate so that the nav bar looks the way you want.

To do so, make a small black rectangle image and include it in your project. Set the background image of the nav bar to this image. Check Translucent. Problem solved! The nav bar is now black opaque in appearance, but it no longer exhibits the bug.



回答4:

Swift version:

class PromptViewSideEffect: UIView {

override func didMoveToSuperview() {
    super.didMoveToSuperview()
    if let superview: UIView  = self.superview {
        let rect: CGRect = superview.bounds
        rect.origin.y += 44
        rect.size.height -= 44
        self.frame = rect
        }
    }
}


回答5:

The problem exists whether your nav bars are opaque or translucent. It sucks that Apple has allowed this heinous bug to plague us for over three years now.

All of these solutions are hacks. My solution is to either A) NEVER use prompts, or B) use them in every single view even if you have to set them to "".