У меня также было много проблем с UIScrollView
составлением нескольких UITextFields
, из которых один или несколько из них были бы скрыты клавиатурой при редактировании.
Вот некоторые вещи, которые следует учитывать, если ваша UIScrollView
не прокручивается должным образом.
1) Убедитесь, что ваш размер содержимого больше размера UIScrollView
. Способ понять UIScrollViews
состоит в том, что UIScrollView
подобен окну просмотра контента, определенного в contentSize. Поэтому, когда UIScrollview
прокручивается куда-либо, contentSize должен быть больше, чем UIScrollView
. Иначе, прокрутка не требуется, так как все, что определено в contentSize, уже видно. Кстати, contentSize по умолчанию = CGSizeZero
.
2) Теперь, когда вы понимаете, что UIScrollView
действительно является окном в вашем «контенте», способ убедиться, что клавиатура не заслоняет ваше «1017 * окно просмотра», состоит в изменении размера UIScrollView
поэтому, когда клавиатура присутствует, у вас есть окно UIScrollView
, размер которого соответствует исходному UIScrollView
frame.size.height минус высота клавиатуры. Это гарантирует, что ваше окно будет только этой маленькой видимой областью.
3) Вот подвох: когда я впервые это реализовал, я подумал, что мне нужно получить CGRect
отредактированного текстового поля и вызвать UIScrollView's
scrollRecToVisible метод. Я реализовал метод UITextFieldDelegate
textFieldDidBeginEditing
с вызовом метода scrollRecToVisible
. Это на самом деле работало со странным побочным эффектом, что прокрутка защелкивала UITextField
в положение. Долгое время я не мог понять, что это было. Затем я прокомментировал метод textFieldDidBeginEditing
Delegate, и все это работает !! (???). Как выяснилось, я считаю, что UIScrollView
фактически неявно переносит отредактированный в настоящее время UITextField
в видимое окно. Моя реализация метода UITextFieldDelegate
и последующий вызов scrollRecToVisible
были излишними и стали причиной странного побочного эффекта.
Итак, вот шаги для правильной прокрутки UITextField
в UIScrollView
на место при появлении клавиатуры.
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.view.window];
keyboardIsShown = NO;
//make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
CGSize scrollContentSize = CGSizeMake(320, 345);
self.scrollView.contentSize = scrollContentSize;
}
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height += (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown. This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`. If we were to resize the `UIScrollView` again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = YES;
}
- Зарегистрируйтесь для получения уведомлений клавиатуры на
viewDidLoad
- Отменить регистрацию для клавиатурных сообщений на
viewDidUnload
- Убедитесь, что
contentSize
установлено и больше, чем UIScrollView
на viewDidLoad
- Сжатие
UIScrollView
при наличии клавиатуры
- Вернуть назад
UIScrollView
, когда клавиатура исчезнет.
- Используйте ivar, чтобы определить, отображается ли уже клавиатура на экране, поскольку уведомления клавиатуры отправляются каждый раз, когда вкладка
UITextField
даже если клавиатура уже присутствует, чтобы избежать сжатия UIScrollView
когда оно уже уменьшилось
Следует отметить, что UIKeyboardWillShowNotification
будет срабатывать, даже если клавиатура уже находится на экране, когда вы нажимаете на другую UITextField
. Я позаботился об этом, используя ivar, чтобы избежать изменения размера UIScrollView
, когда клавиатура уже на экране. Непреднамеренное изменение размера UIScrollView
, когда клавиатура уже есть, приведет к катастрофическим последствиям!
Надеюсь, этот код избавит некоторых из вас от головной боли.