Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 11 UINavigationBar bar button items alignment

Tags:

ios11

I am upgrading my application to iOS 11 and I am seeing some problems with the navigation bar, part of my problems have already asked questions here, so I won't mention them in this question.

The particular problem in question is that the navigation bar's bar button items are spaced differently. My main left and right bar button items are closer to the screen's horizontal center now and I can't move them near to the screen edges. In the past I have used a custom UIButton subclass and created bar button items with custom view. The alignment solution were alignmentRectInsets and contentEdgeInsets, now I couldn't manage to produce the expected results using this approach.

Edit:
I have retested with iOS 11 beta 2 and the issue remains.

Edit 2: I Have retested with iOS beta 3 and the issue remains.

like image 421
Georgi Boyadzhiev Avatar asked Jun 21 '17 13:06

Georgi Boyadzhiev


People also ask

How do I customize my navigation bar?

From Settings, tap Display, and then tap Navigation bar. Make sure Buttons is selected, and then you can choose your desired button setup at the bottom of the screen. Note: This option will also affect the location you swipe when using Swipe gestures.

How do I customize the navigation bar in Swift?

Go to the ViewController. swift file and add the ViewDidAppear method. a nav helper variable which saves typing. the Navigation Bar Style is set to black and the tint color is set to yellow, this will change the bar button items to yellow.

What is Scrolledgeappearance?

The appearance settings for the navigation bar when the edge of scrollable content aligns with the edge of the navigation bar.


2 Answers

Now in iOS 11 you can manage UINavigationBarContentView to adjust left and right constraints, and UIStackView to adjust buttons (or other elements).

This is my solution for a navigation bar with items on left and right. Also it fixes if you have several buttons together in one side.

- (void) updateNavigationBar {
    for(UIView *view in self.navigationBar.subviews) {
        if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {

            // Adjust left and right constraints of the content view 
            for(NSLayoutConstraint *ctr in view.constraints) {
                if(ctr.firstAttribute == NSLayoutAttributeLeading || ctr.secondAttribute == NSLayoutAttributeLeading) {
                    ctr.constant = 0.f;
                } else if(ctr.firstAttribute == NSLayoutAttributeTrailing || ctr.secondAttribute == NSLayoutAttributeTrailing) {
                    ctr.constant = 0.f;
                }
            }

            // Adjust constraints between items in stack view
            for(UIView *subview in view.subviews) {
                if([subview isKindOfClass:[UIStackView class]]) {
                    for(NSLayoutConstraint *ctr in subview.constraints) {
                        if(ctr.firstAttribute == NSLayoutAttributeWidth || ctr.secondAttribute == NSLayoutAttributeWidth) {
                            ctr.constant = 0.f;
                        }
                    }
                }
            }
        }
    }
}


As you see it is not necessary to add more constraints, as other people have done. There are already defined constraints so they can be changed.

like image 154
JonyMateos Avatar answered Oct 13 '22 18:10

JonyMateos


After about two days, here is the simplest and safest solution I could come up with. This solution only works with custom view bar button items, the code for which is included. It is important to note that the left and right margins on the navigation bar have not changed from iOS10 to iOS11 - they are still 16px. Such a large margin makes it difficult to have a sufficiently large click region.

Bar buttons are now layed out with UIStackView's. The prior method of shifting those buttons closer to the margin involved using negative fixed spaces which these stack views cannot handle.

Subclass UINavigationBar

FWNavigationBar.h

@interface FWNavigationBar : UINavigationBar

@end

FWNavigationBar.m

#import "FWNavigationBar.h"

@implementation FWNavigationBar

- (void)layoutSubviews {
    [super layoutSubviews];

    if (@available(iOS 11, *)) {
        self.layoutMargins = UIEdgeInsetsZero;
        
        for (UIView *subview in self.subviews) {
            if ([NSStringFromClass([subview class]) containsString:@"ContentView"]) {
                subview.layoutMargins = UIEdgeInsetsZero;
            }
        }
    }
}

@end

Using the UINavigationController

#import "FWNavigationBar.h"

UINavigationController *controller = [UINavigationController initWithNavigationBarClass:[FWNavigationBar class] toolbarClass:nil];
[controller setViewControllers:@[rootViewController] animated:NO];

Creating a UIBarButton

Place this code either in a UIBarButton category or in the file you plan on using the bar button which will return an identical looking bar button item using a UIButton.

+ (UIBarButtonItem *)barButtonWithImage:(UIImage *)image target:(id)target action:(SEL)action {
   UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
   //Note: Only iOS 11 and up supports constraints on custom bar button views
   button.frame = CGRectMake(0, 0, image.size.width, image.size.height);

   button.tintColor = [UIColor lightGrayColor];//Adjust the highlight color

   [button setImage:image forState:UIControlStateNormal];
   //Tint color only applies to this image
   [button setImage:[image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateHighlighted];
   [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    
   return [[UIBarButtonItem alloc] initWithCustomView:button];
}

Setting the bar button in your controller

- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonWithImage:[UIImage imageNamed:@"your_button_image"] target:self action:@selector(leftButtonPressed)];
}

Lastly, I would recommend leaving the left and right margins at zero and just adjusting the position of the button within your image. This will allow for you to take advantage of the full clickable region up to the edge of the screen. The same goes for the height of your image - make sure the height is 44 points.

like image 7
Josh Bernfeld Avatar answered Oct 13 '22 17:10

Josh Bernfeld