Я работаю над библиотекой с открытым исходным кодом, чтобы обеспечить представление ввода текста в стиле iMessage — MessageComposerView (относится к вопросу). Представление будет прилипать к клавиатуре, как inputAccessoryView
, и увеличиваться вместе с текстом, но не исчезнет, когда это сделает клавиатура.
Недавно я столкнулся с невыносимой проблемой при повороте этого пользовательского UIView, который появляется только в том случае, если представление было создано через initWithFrame
. В основном в тот момент, когда было перехвачено уведомление UIDeviceOrientationDidChangeNotification, если представление было создано через initWithFrame
, UIInterfaceOrientation и кадр еще НЕ были обновлены. Вот оба способа создания экземпляров.
loadNibNamed
:
self.messageComposerView = [[NSBundle mainBundle] loadNibNamed:@"MessageComposerView" owner:nil options:nil][0];
self.messageComposerView.frame = CGRectMake(0,
self.view.frame.size.height - self.messageComposerView.frame.size.height,
self.messageComposerView.frame.size.width,
self.messageComposerView.frame.size.height);
initWithFrame
:
self.messageComposerView = [[MessageComposerView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height-54, 320, 54)];
При запуске через loadNibNamed
и повороте в альбомную, при получении уведомления UIDeviceOrientationDidChangeNotification
:
UIDeviceOrientation
= [[объект уведомления] ориентация] = UIInterfaceOrientationLandscapeLeftUIInterfaceOrientation
= [Общее приложение UIApplication].statusBarOrientation = UIDeviceOrientationLandscapeRightself.frame.size
= (ширина=480, высота=90)
Здесь важно отметить, что и интерфейс, и устройство имеют альбомную ориентацию, а ширина уже была изменена на альбомную (тестирование на симуляторе iPhone 6.1). Теперь выполняем тот же тест, но с использованием initWithFrame
:
UIDeviceOrientation
= [[объект уведомления] ориентация] = UIDeviceOrientationLandscapeRightUIInterfaceOrientation
= [Общее приложение UIApplication].statusBarOrientation = UIInterfaceOrientationPortraitself.frame.size
= (ширина=320, высота=54)
На этот раз обратите внимание, что ориентация интерфейса по-прежнему книжная и ширина кадра НЕ изменилась на альбомную. Если я установлю точку останова в методе setFrame:(CGRect)frame
, я увижу, что фрейм установлен в ландшафтный фрейм ПОСЛЕ того, как UIDeviceOrientationDidChangeNotification был перехвачен и обработан.
Оба метода инициализации имеют почти идентичные настройки:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.frame = frame;
self.sendButton = [[UIButton alloc] initWithFrame:CGRectZero];
self.messageTextView = [[UITextView alloc] initWithFrame:CGRectZero];
[self setup];
[self addSubview:self.sendButton];
[self addSubview:self.messageTextView];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
Когда setup
выполняет необходимые настройки вида:
- (void)setup {
self.backgroundColor = [UIColor lightGrayColor];
self.autoresizesSubviews = YES;
self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
CGRect sendButtonFrame = self.bounds;
sendButtonFrame.size.width = 50;
sendButtonFrame.size.height = 34;
sendButtonFrame.origin.x = self.frame.size.width - kComposerBackgroundRightPadding - sendButtonFrame.size.width;
sendButtonFrame.origin.y = kComposerBackgroundRightPadding;
self.sendButton.frame = sendButtonFrame;
self.sendButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;
self.sendButton.layer.cornerRadius = 5;
[self.sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.sendButton setTitleColor:[UIColor colorWithRed:210/255.0 green:210/255.0 blue:210/255.0 alpha:1.0] forState:UIControlStateHighlighted];
[self.sendButton setTitleColor:[UIColor grayColor] forState:UIControlStateSelected];
[self.sendButton setBackgroundColor:[UIColor orangeColor]];
[self.sendButton setTitle:@"Send" forState:UIControlStateNormal];
self.sendButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
CGRect messageTextViewFrame = self.bounds;
messageTextViewFrame.origin.x = kComposerBackgroundLeftPadding;
messageTextViewFrame.origin.y = kComposerBackgroundTopPadding;
messageTextViewFrame.size.width = self.frame.size.width - kComposerBackgroundLeftPadding - kComposerTextViewButtonBetweenPadding - sendButtonFrame.size.width - kComposerBackgroundRightPadding;
messageTextViewFrame.size.height = 34;
self.messageTextView.frame = messageTextViewFrame;
self.messageTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.messageTextView.showsHorizontalScrollIndicator = NO;
self.messageTextView.layer.cornerRadius = 5;
self.messageTextView.font = [UIFont systemFontOfSize:14];
self.messageTextView.delegate = self;
[self addNotifications];
[self resizeTextViewForText:@"" animated:NO];
}
Итак, мой вопрос: почему моя пользовательская инициализация UIView через initWithFrame
по-прежнему имеет портретную рамку и ориентацию интерфейса, а также время получения UIDeviceOrientationDidChangeNotification. Я использую это уведомление, чтобы выполнить настройку кадра, и мне нужно, чтобы ширина уже была обновлена до ширины ландшафта.
Я надеюсь, что есть какое-то свойство авторотации, которого мне не хватает в программной настройке, которая похоронена где-то в XIB, но просто не могу ее найти. Я просмотрел, наверное, дюжину UIDeviceOrientationDidChangeNotification
сообщений stackoverflow, но не нашел решения.
self.frame = frame;
в коде инициализации. Вызовsuper
уже должен это делать. - person Michael Enriquez   schedule 17.11.2013