IOS 11 UINavigationBar выравнивание элементов панели бара

Я обновляю свое приложение до iOS 11, и я вижу некоторые проблемы с навигационной панелью, часть моих проблем уже задавала вопросы здесь, поэтому я не буду упоминать их в этом вопросе.

Особая проблема заключается в том, что элементы кнопки панели навигации расположены по-разному. Мои главные элементы левой и правой кнопки бара ближе к горизонтальному центру экрана теперь, и я не могу перемещать их близко к краям экрана. Раньше я использовал собственный подкласс UIButton и создал элементы панели с настраиваемым представлением. Решение выравнивания было alignmentRectInsets и contentEdgeInsets, теперь я не смог выполнить ожидаемые результаты с использованием этого подхода.

Edit:
Я перепробовал iOS 11 beta 2, и проблема остается.

Изменить 2: Я протестировал с бета-версией iOS 3, и проблема остается.

Ответы

Ответ 1

Есть хорошая статья об этом: http://www.matrixprojects.net/p/uibarbuttonitem-ios11/

Используя это, мы можем, по крайней мере, направить правые панели вправо до тех пор, пока он не оставит 8-пиксельный край от завершения UINavigationBar.

Разъясняется очень хорошо.

Ответ 2

Примерно через два дня, это самое простое и безопасное решение, которое я мог бы придумать. Это решение работает только с настраиваемыми элементами кнопки панели поиска, код для которых включен. Важно отметить, что левое и правое поля на навигационной панели не изменились с iOS10 на iOS11 - они все еще 16 пикселей. Такой большой запас затрудняет наличие достаточно большой области щелчков.

Теперь кнопки Bar теперь выложены с помощью UIStackView. Предыдущий способ смещения этих кнопок ближе к краю, используемому с использованием отрицательных фиксированных пространств, которые эти представления стека не могут обрабатывать.

Подкласс 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

Использование UINavigationController

#import "FWNavigationBar.h"

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

Создание UIBarButton

Поместите этот код либо в категорию UIBarButton, либо в файл, который вы планируете использовать с помощью кнопки панели, которая вернет идентичный элемент кнопки панели с помощью 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];
}

Установка кнопки панели в контроллере

- (void)viewDidLoad {
    [super viewDidLoad];

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

Наконец, я бы рекомендовал оставить левый и правый поля в нуле и просто настроить положение кнопки в вашем изображении. Это позволит вам воспользоваться преимуществами полного кликабельного региона до края экрана. То же самое касается высоты вашего изображения - убедитесь, что высота равна 44 точкам.

Ответ 3

Теперь в iOS 11 вы можете управлять UINavigationBarContentView для настройки левого и правого ограничений и UIStackView для настройки кнопок (или других элементов).

Это мое решение для панели навигации с элементами слева и справа. Также он исправляет, если у вас несколько кнопок вместе в одной стороне.

- (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;
                        }
                    }
                }
            }
        }
    }
}


Как вы видите, нет необходимости добавлять больше ограничений, как это делали другие люди. Существуют уже определенные ограничения, поэтому их можно изменить.

Ответ 4

Я заметил подобную проблему.

Я сообщил Apple Радар для аналогичной проблемы, которую мы заметили, # 32674764, если вы хотите обратиться к ней, если вы создаете радар.

Я также создал нить в Apple forum, но обратной связи пока нет: https://forums.developer.apple.com/message/234654

Ответ 5

Решение 1: В свете ответа Apple, что это ожидаемое поведение, мы работали над проблемой, удалив панель инструментов и добавив пользовательский вид.

Я понимаю, что это может быть невозможно во всех случаях, но обычный UIView намного проще настраивать на внешний вид приложения, чем панель инструментов и панель навигации, где Apple контролирует позиционирование кнопок.

Вместо того, чтобы настраивать нашу пользовательскую кнопку как пользовательский вид объекта кнопки ui bar, мы установили его как подпункт пустых кнопок ui в пользовательском представлении.

Сделав это, мы смогли вернуться к тому же взгляду нашего приложения ios 10

Решение 2: Немного беспорядочно, мы завернули нашу пользовательскую кнопку просмотра в внешнем UIButton, чтобы можно было установить местоположение фрейма. Это делает внешний левый край кнопки неуправляемой, к сожалению, но корректирует внешний вид положения кнопки. Пример:

UIButton* outerButton = [UIButton new]; //the wrapper button
BorderedButton* button = [self initBorderedButton]; //the custom button
[button setTitle:label forState:UIControlStateNormal];
[button setFrame:CGRectMake(-10, 0, [label length] * 4 + 35, 30)];
[button addTarget:controller action:@selector(popCurrentViewController) forControlEvents:UIControlEventTouchUpInside];
[outerButton addSubview:button]; //add custom button to outer wrapper button
[outerButton setFrameWidth:button.frameWidth]; //make sure title gives button appropriate space
controller.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:outerButton]; //add wrapper button to the navigation bar
controller.navigationItem.hidesBackButton = YES;

Используя этот метод, мы сохраняем нашу панель навигации и можем поместить кнопку туда, где это необходимо.

Edit: Мы обнаружили, что решение 2 не работает на ios 10, вероятно, это затронет только крошечный процент разработчиков, вынужденных быть обратно совместимыми.

Решение 3

То, что нас больше беспокоило внутреннее переполнение кнопок, заключалось в том, что заголовок навигационной панели переместился в пользовательскую левую кнопку, размер полей был менее важным и использовался как инструмент для создания пространства, Решение состоит в том, чтобы просто добавить элемент с разделителем в левые элементы.

UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithCustomView:button];
UIBarButtonItem* spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
controller.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:backButton, spacer, nil];

Ответ 6

Взято из этого ответа: теперь BarButtons использует Autolayout и, следовательно, требует ограничений.

if #available(iOS 9.0, *) {
  cButton.widthAnchor.constraint(equalToConstant: customViewButton.width).isActive = true
  cButton.heightAnchor.constraint(equalToConstant: customViewButton.height).isActive = true
}

Цель C

if (@available(iOS 9, *)) {
  [cButton.widthAnchor constraintEqualToConstant: standardButtonSize.width].active = YES;
  [cButton.heightAnchor constraintEqualToConstant: standardButtonSize.height].active = YES;
}

Ответ 7

Быстрая версия встроенного подпрограммы UINavigationBar в стиле thedeveloper3214 layoutSubviews (fooobar.com/info/387260/...):

override func layoutSubviews() {
    super.layoutSubviews();
    if #available(iOS 11, *){
        self.layoutMargins = UIEdgeInsets()
        for subview in self.subviews {
            if String(describing: subview.classForCoder).contains("ContentView") {
                let oldEdges = subview.layoutMargins
                subview.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: oldEdges.right)
            }
        }
    }
}