iOS 11 navigationItem.titleView Ширина не установлена
Наблюдение за поведением на iOS11 с навигационным элементом Item.titleView, где ширина titleView не является полной шириной экрана.
У меня есть пользовательский вид, который я установил как titleView. До iOS11 представление будет заполнять область панели навигации. Но iOS 11 не изменяет размеры, чтобы заполнить ширину экрана.
Я пытался установить рамку представления перед настройкой titleView, но не повезло. Я пытался заставить суперпредставление titleViews также ограничить макет, но безуспешно.
Скриншоты прилагаются:
iOS10:
iOS11:
Кто-нибудь еще испытывает это?
15 ответов
Я понял. Мне пришлось переопределить метод получения intrinsicContentSize для представления и текстового поля.
Я установил ширину в CGFloat.greatestFiniteMagnitude, чтобы она всегда была такой же ширины, как и экран.
Обновить:
Поскольку я потратил пару часов на эту проблему, надеюсь, что кто-то еще наверстает упущенное, собрав все вместе
Я создал собственный подкласс TitleView
, называется CustomTitleView
вот код:
import UIKit
class CustomTitleView: UIView {
override var intrinsicContentSize: CGSize {
return UILayoutFittingExpandedSize
}
}
и самая важная часть, которую я пропустил с самого начала, заключалась в следующем:
Используя ответ @falkon, вот код:
Добавьте этот код в представление, которое используется в качестве titleView
override var intrinsicContentSize: CGSize {
return UILayoutFittingExpandedSize
}
Исправили это, создав подкласс UIView и присвоив его заголовку UINavigationController
Objective-C:
#import "FLWCustomTitleView.h"
@implementation FLWCustomTitleView
- (CGSize )intrinsicContentSize {
return UILayoutFittingExpandedSize;
}
@end
Установка intrinsicContentSize
в UILayoutFittingExpandedSize
works fine as well
Я должен был соответствовать UIImageView как навигация Item.titleView. Соотношение сторон действительно подходящее, но intrinsicContentSize сделало его большим. Масштабирование изображения привело к снижению качества изображения. Установка макетов якорей сработала у меня:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 30)];
[imageView setImage:image];
[imageView.widthAnchor constraintEqualToConstant:80].active = YES;
[imageView.heightAnchor constraintEqualToConstant:30].active = YES;
[imageView setContentMode:UIViewContentModeScaleAspectFit];
self.navigationItem.titleView = imageView;
Дополнение к существующим ответам:
Если ваш пользовательский вид заголовка - это вид, который по умолчанию уже имеет внутренний размер контента (кроме .zero
), например UILabel
, UITextView
или UIButton
, вы можете просто установить
yourCustomTitleView.translatesAutoresizingMaskIntoConstraints = false
и он автоматически настроится так, чтобы просто заключать его содержимое, но никогда не совпадать с левым и правым представлениями элементов.
Например, вы можете перетащить кнопку в область просмотра заголовка панели навигации в Интерфейсном Разработчике, создать розетку titleButton
для этого в вашем представлении контроллера, а затем сделать
override func viewDidLoad() {
super.viewDidLoad()
titleButton.translatesAutoresizingMaskIntoConstraints = false
}
Swift 4.2 Версия ответа Еди
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 80, height: 30))
imageView.image = image
imageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 30).isActive = true
imageView.contentMode = .scaleAspectFit
navigationItem.titleView = imageView
Преобразован с помощью Swiftify.
Этот класс сделает свое дело. Убедитесь, что вы установили класс своего пользовательского представления на этот:
import UIKit
class TitleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) {
super.init(coder: coder)
translatesAutoresizingMaskIntoConstraints = false
}
override var intrinsicContentSize: CGSize {
CGSize(width: UIView.layoutFittingExpandedSize.width, height: self.bounds.height)
}
}
Вы также можете использовать ограничения, если вы не хотите переопределять intrinsicContentSize
, Вот демо SnapKit
self.navigationItem.titleView = titleView
if #available(iOS 11, *) {
titleView.snp.makeConstraints({ (make) in
make.width.equalTo(250) // fixed width
make.height.equalTo(30) // less than 44(height of naviagtion bar)
})
}else {
titleView.frame = ...
}
Но если на любой боковой (левой или правой) навигационной панели имеется более одного навигационного элемента, вам следует использовать intrinsicContentSize;
Когда у вас есть UIView как подпредставление внутри CustomTitleView, решение intrinsicContentSize не работает, для меня только в XCODE 9 в iOS 11. так что я сделал, как показано ниже, прекрасно работает для меня, может это кому-то поможет.
@interface CustomTitleView : UIView
@property (weak, nonatomic) IBOutlet UIView *doubleTitleView;
@end
@implementation CustomTitleView
- (void)awakeFromNib {
[super awakeFromNib];
int width = _doubleTitleView.frame.size.width;
int height = _doubleTitleView.frame.size.height;
if (width != 0 && height != 0) {
NSLayoutConstraint *widthConstraint = [_doubleTitleView.widthAnchor constraintEqualToConstant:width];
NSLayoutConstraint *heightConstraint = [_doubleTitleView.heightAnchor constraintEqualToConstant:height];
[_doubleTitleView addConstraint:heightConstraint];
[_doubleTitleView addConstraint:widthConstraint];
[heightConstraint setActive:TRUE];
[widthConstraint setActive:TRUE];
}
}
Наиболее важным является то, что вам нужно перезаписать customTitleView в качестве вашего titleView:
self.navigationItem.titleView = [self titleView];
#pragma mark - getter
- (UIView *)titleView {
UIView *navTitleView = [HFCalenderTitleView new];
navTitleView.frame = CGRectMake(0.0, 0.0, HorizontalFrom750(200.0), 44.0);
[navTitleView addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(navTitleView);
}];
CGFloat btnWidth = 30.0;
[navTitleView addSubview:self.previousButton];
self.previousButton.imageEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 15.0);
[self.previousButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(navTitleView);
make.top.bottom.equalTo(navTitleView);
make.width.equalTo(@(btnWidth));
}];
[navTitleView addSubview:self.nextBtn];
self.nextBtn.imageEdgeInsets = UIEdgeInsetsMake(0.0, 15.0, 0.0, 0.0);
[self.nextBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(navTitleView);
make.top.bottom.equalTo(navTitleView);
make.width.equalTo(@(btnWidth));
}];
return navTitleView;
}
#pragma mark - customTitleView
#import "HFCalenderTitleView.h"
@implementation HFCalenderTitleView
- (CGSize)intrinsicContentSize{
return CGSizeMake(HorizontalFrom750(200.0), 40); // the target size
}
У меня была такая же проблема, но с настройкой UIImage
как navigationItem
titleView
То, что я сделал, я масштабировал изображение до необходимого размера, используя ниже:
-(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
И назовите это следующим образом:
-(void)setHeaderImage{
UIImage * image = [self imageWithImage:[UIImage imageNamed:@"headerImage"] scaledToSize:CGSizeMake(150, 27)];
UIImageView * imageView = [[UIImageView alloc]initWithImage:image];
imageView.frame = CGRectMake(0, 0, 150, 27);
imageView.contentMode = UIViewContentModeScaleAspectFit;
self.navigationItem.titleView = imageView;
}
по настройке-настройке вашего навигационного контроллера
все, что вам нужно сделать, это установить для translatesAutoresizingMaskIntoConstraints значение falsecheck apple doc
Обратите внимание, что ограничения маски автоматического изменения размера полностью определяют размер и положение представления; следовательно, вы не можете добавлять дополнительные ограничения для изменения этого размера или положения без возникновения конфликтов. Если вы хотите использовать Auto Layout для динамического расчета размера и положения вашего представления, вы должны установить для этого свойства значение false.
затем назначьте ему желаемую ширину
navigationItem.titleView?.translatesAutoresizingMaskIntoConstraints = false
lazy var titleWidth = view.frame.size.width / 2
navigationItem.titleView?.constrainWidth(constant: titleWidth)
return UILayoutFittingExpandedSize
мне не помогло, потому что представление было добавлено по вертикали еще несколько раз для заполнения макета
Решение было переопределить intrinsicContentSize
в настраиваемом представлении настройка ширины до максимальной ширины экрана:
- (CGSize)intrinsicContentSize {
//fills empty space. View will be resized to be smaller, but if it is too small - then it stays too small
CGRect frame = self.frame;
frame.size.width = MAX(SCREEN_WIDTH, SCREEN_HEIGHT);
return frame.size;
}
Попробуйте использовать стандартный UISearchBar / UISearchController
На самом деле, что вам нужно сделать - если вы можете использовать стандартный UISearchBar /, то UISearchController должен отображать строку поиска следующим образом, который учитывает безопасную область и, таким образом, выглядит идеально на iPhone X и в каждой ориентации устройства:
func presentSearchController() {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.text = "any text"
if #available(iOS 11.0, *) {
self.navigationItem.searchController = searchController
searchController.isActive = true
} else {
present(searchController, animated: true, completion: nil)
}
}
Рекомендации
https://developer.apple.com/videos/play/fall2017/201/ https://medium.com/@PavelGnatyuk/large-title-and-search-in-ios-11-514d5e020cee