UINavigationBar с большими заголовками - как найти дополнительную высоту в iOS 11
При использовании prefersLargeTitles для UINavigationController
"s UINavigationBar
в iOS 11
Панель навигации увеличивает высоту. На iPhone, который я проверял, это увеличение с 44 до 96, но я думаю, что эти цифры могут меняться для каждого устройства (или, по крайней мере, нам нужно кодировать так, как если бы они могли).
Я хочу программно найти "дополнительную" высоту - высоту большой области заголовков, которая добавляется ниже традиционной UINavigationBar
когда отображается большой заголовок. Я могу легко найти всю высоту строки с отображением большого заголовка, но есть ли способ программно найти высоту только одной части большого заголовка (без какого-либо жесткого кодирования)?
Причина, по которой мне это нужно, состоит в том, что бывают моменты, когда я хочу программно прокрутить до верха UITableView, потянув вниз большой заголовок (который прокручивается вверх под панелью навигации "обычная высота"), чтобы он отображался, и Смещение контента мне нужно, это дополнительная высота панели навигации. Я мог бы использовать общую высоту навигационной панели, но это привело бы к слишком большому UITableView. Чтобы сделать это сейчас, мне нужно жестко, как показано ниже:
[self.tableView setContentOffset:CGPointMake(0, -52) animated:NO];
6 ответов
Я думаю, что вы не найдете способа четко решить вашу проблему. То, что вы просите, является частью внутренней панели навигации, которая не предоставляется пользователю. Тем не менее, я думаю, что могу предложить вам обходной путь.
Чтобы понять это, давайте взглянем на панель навигации (с включенными большими заголовками) в отладчике представления. Как вы можете видеть на изображении ниже, есть дополнительный вид, содержащий большой заголовок для конкретного контроллера вида. Это представление отсутствует, если вы не поддерживаете большие заголовки.
По сути, вы хотите знать высоту этого представления.
Это мое предлагаемое решение / обходной путь
extension UINavigationBar
{
var lagreTitleHeight: CGFloat {
let maxSize = self.subviews
.filter { $0.frame.origin.y > 0 }
.max { $0.frame.origin.y < $1.frame.origin.y }
.map { $0.frame.size }
return maxSize?.height ?? 0
}
}
Что оно делает
- Отфильтровывает подпредставления, которые начинаются в верхней части панели навигации. Скорее всего, это фон или область навигации, они нам не нужны.
- Находит самое низкое подпредставление в в панели навигации.
- Сопоставляет полученный кадр подпредставления с размером кадра.
- Возвращает высоту найденного подпредставления или 0, если ничего не найдено.
Очевидным недостатком этого подхода является то, что он тесно связан со структурой панели навигации, которая может измениться в будущем. Однако вряд ли вы получите что-то большее, чем тот или иной подвох.
Результат выполнения должен выглядеть следующим образом.
print("Extra height: \(navigationController!.navigationBar.lagreTitleHeight)")
Extra height: 52.0
Похоже на звонок
navigationBar.sizeToFit()
заставляет
navigationBar
чтобы отрегулировать его размер при отображении большого заголовка. Таким образом, вы можете легко рассчитать верхнюю безопасную зону. Решение, которое мы придумали, следующее:
self.navigationController?.navigationBar.sizeToFit()
let navigationBarOffset = navigationController?.navigationBar.frame.origin.y ?? 0
let navigationBarHeight = navigationController?.navigationBar.frame.height ?? 0
let offset = -navigationBarOffset - navigationBarHeight
if collectionView.contentOffset.y > offset {
let contentOffset = CGPoint(x: 0, y: offset)
collectionView.setContentOffset(contentOffset, animated: true)
}
Насколько я понимаю, у вас есть источник tableView под навигационной панелью, при y = 0 в представлении вашего UIViewController.
У вашего tableView должна быть привязана его верхняя граница к верхней направляющей макета, или используйте новую безопасную область. Таким образом, вам не придется программно вычислять размер панели навигации.
Если вы никогда не использовали его, взгляните на авто-макет.
Вы можете просто прокрутить верхнюю часть таблицы, не зная размера панели навигации. UITableView
поставляется с API для этого.
Опция 1
// Get the first index path. You might want to check here whether data source item exists.
NSIndexPath *firstIndexPath = [NSIndexPath indexPathForRow:0
inSection:0];
// Scroll to it. You can play with scroll position to get what you want
[tableView scrollToRowAtIndexPath:firstIndexPath
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
Вариант 2
CGPoint offset = CGPointMake(0.0, -tableView.contentInset.top);
[tableView setContentOffset:offset animated:YES];
if (@available(iOS 11.0, *)) {
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
Вы можете использовать этот код. И попробуй еще раз. Этот код может сделать ваш tableView.frame.y с начала 0px.
Я только что испытал эту же проблему.
-(void)layoutSubviews{
[super layoutSubviews];
CGRect rectStatusBar = [[UIApplication sharedApplication] statusBarFrame];
if (rectStatusBar.size.height==44.f) {
//statusBar shows
}else{
if (@available(iOS 11.0, *)) {
for ( UIView*view in self.subviews) {
if ([NSStringFromClass(view.classForCoder) isEqualToString:@"_UINavigationBarContentView"]) {
view.frame = CGRectMake( 0,20,view.frame.size.width,44);
}
else if ([NSStringFromClass(view.classForCoder) isEqualToString:@"_UIBarBackground"]) {
view.frame = CGRectMake(0,0,view.frame.size.width, 64);
}
}
}
}
}