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)
}
}
}
}