Перемещение UIView вверх, когда клавиатура появляется в iOS
У меня есть UIView, это не внутри UIScrollView. Я хотел бы переместить свой вид, когда появится клавиатура. Прежде чем я попытался использовать это решение:Как я могу сделать UITextField двигаться вверх, когда клавиатура присутствует?.
Он работал хорошо. Но после вставки данных в текстовые поля он переносит меня в другое представление, и когда я возвращаюсь к этой странице, он просто прыгает, и я не мог видеть свои текстовые поля. Есть ли лучшее решение для этой проблемы?
17 ответов:
используйте следующий код, чтобы показать и скрыть клавиатуру
//Declare a delegate, assign your textField to the delegate and then include these methods -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; return YES; } - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; [self.view endEditing:YES]; return YES; } - (void)keyboardDidShow:(NSNotification *)notification { // Assign new frame to your view [self.view setFrame:CGRectMake(0,-110,320,460)]; //here taken -110 for example i.e. your view will be scrolled to -110. change its value according to your requirement. } -(void)keyboardDidHide:(NSNotification *)notification { [self.view setFrame:CGRectMake(0,0,320,460)]; }
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - keyboard movements - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = -keyboardSize.height; self.view.frame = f; }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = 0.0f; self.view.frame = f; }]; }
Я написал небольшую категорию на
UIView
что управляет временно прокручивать вещи вокруг без необходимости обернуть все это вUIScrollView
. Мое использование глагола "scroll" здесь, возможно, не идеально, потому что это может заставить вас думать, что есть представление прокрутки, и нет-мы просто анимируем позициюUIView
(илиUIView
подкласс).есть куча магических чисел, встроенных в это, которые подходят для моей формы и макета, которые могут не быть подходит для вашего, поэтому я рекомендую настроить это в соответствии с вашими конкретными потребностями.
UIView + FormScroll.h:
#import <Foundation/Foundation.h> @interface UIView (FormScroll) -(void)scrollToY:(float)y; -(void)scrollToView:(UIView *)view; -(void)scrollElement:(UIView *)view toPoint:(float)y; @end
UIView + FormScroll.м:
#import "UIView+FormScroll.h" @implementation UIView (FormScroll) -(void)scrollToY:(float)y { [UIView beginAnimations:@"registerScroll" context:NULL]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.4]; self.transform = CGAffineTransformMakeTranslation(0, y); [UIView commitAnimations]; } -(void)scrollToView:(UIView *)view { CGRect theFrame = view.frame; float y = theFrame.origin.y - 15; y -= (y/1.7); [self scrollToY:-y]; } -(void)scrollElement:(UIView *)view toPoint:(float)y { CGRect theFrame = view.frame; float orig_y = theFrame.origin.y; float diff = y - orig_y; if (diff < 0) { [self scrollToY:diff]; } else { [self scrollToY:0]; } } @end
импортируйте это в свой UIViewController, а затем вы можете сделать
- (void)textFieldDidBeginEditing:(UITextField *)textField { [self.view scrollToView:textField]; } -(void) textFieldDidEndEditing:(UITextField *)textField { [self.view scrollToY:0]; [textField resignFirstResponder]; }
...или еще что-нибудь. Эта категория дает вам три довольно хороших способа настроить положение вида.
привязка представления к клавиатуре также является опцией (см. GIF в нижней части ответа)
Swift 4
используйте расширение: (не был полностью протестирован)
extension UIView{ func bindToKeyboard(){ NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil) } func unbindToKeyboard(){ NotificationCenter.default.removeObserver(self, name: Notification.Name.UIKeyboardWillChangeFrame, object: nil) } @objc func keyboardWillChange(notification: Notification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y+=deltaY },completion: nil) } }
Swift 2 + 3
использовать расширение:
extension UIView{ func bindToKeyboard(){ NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil) } func keyboardWillChange(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue() let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue() let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y+=deltaY },completion: nil) } }
использование:
// view did load... textField.bindToKeyboard()
...
// view unload textField.unbindToKeyboard()
важно
Не забудьте удалить наблюдателя, когда вид разгрузка
нашел theDuncs ответ очень полезно и ниже вы можете найти мою собственную (рефакторинг) версию:
Основные Изменения
- теперь получаю размер клавиатуры динамически, а не жесткого кодирования значений
- извлек анимацию UIView в свой собственный метод предотвратить дублирование кода
- допустимая длительность, которая должна быть передана в метод, а не быть жестко закодировано
- (void)viewWillAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; }
- (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; float newVerticalPosition = -keyboardSize.height; [self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f]; } - (void)keyboardWillHide:(NSNotification *)notification { [self moveFrameToVerticalPosition:0.0f forDuration:0.3f]; } - (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration { CGRect frame = self.view.frame; frame.origin.y = position; [UIView animateWithDuration:duration animations:^{ self.view.frame = frame; }]; }
на основе решения Даниэля кром. Это версия в swift 3.0. Отлично работает с AutoLayout, и перемещает весь вид при появлении клавиатуры.
extension UIView { func bindToKeyboard(){ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) } func unbindFromKeyboard(){ NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) } @objc func keyboardWillChange(notification: NSNotification) { guard let userInfo = notification.userInfo else { return } let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y += deltaY }) } }
как его использовать: Добавить на
viewDidLoad
как:override func viewDidLoad() { super.viewDidLoad() view.bindToKeyboard() }
и добавить
unbindFromKeyboard
функции деинициализации:deinit { view.unbindFromKeyboard() }
для всех проблем, связанных с клавиатурой просто используйте IQKeyBoardManager это полезно. https://github.com/hackiftekhar/IQKeyboardManager.
попробуйте это:-
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil]; -(void) keyboardDidShow: (NSNotification *)notif { CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height+[self getTableView].tableFooterView.frame.size.height, 0.0); [self getTableView].contentInset = contentInsets; [self getTableView].scrollIndicatorInsets = contentInsets; CGRect rect = self.frame; rect.size.height -= keyboardSize.height; if (!CGRectContainsPoint(rect, self.frame.origin)) { CGPoint scrollPoint = CGPointMake(0.0, self.frame.origin.y - (keyboardSize.height - self.frame.size.height)); [[self getTableView] setContentOffset:scrollPoint animated:YES]; } } -(void) keyboardDidHide: (NSNotification *)notif { UIEdgeInsets contentInsets = UIEdgeInsetsZero; [self getTableView].contentInset = contentInsets; [self getTableView].scrollIndicatorInsets = contentInsets; }
на основе ответ theDunc но написан на Swift с автозапуском.
@IBOutlet weak var bottomConstraint: NSLayoutConstraint! // connect the bottom of the view you want to move to the bottom layout guide override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ConversationViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ConversationViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil) } override func viewWillDisappear(animated: Bool) { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) super.viewWillDisappear(animated) } // MARK: - Keyboard events func keyboardWillShow(notification: NSNotification) { if let userInfo = notification.userInfo, keyboardFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] { let keyboardSize = keyboardFrame.CGRectValue().size self.bottomConstraint.constant = keyboardSize.height UIView.animateWithDuration(0.3) { self.view.layoutIfNeeded() } } } func keyboardWillHide(notification: NSNotification) { self.bottomConstraint.constant = 0 UIView.animateWithDuration(0.3) { self.view.layoutIfNeeded() } }
я реализовал пользовательский контроллер, который динамически вычисляет размер клавиш, прокрутки, текстовые поля, когда он появляется и исчезает, даже при вращении устройства. Работает со всеми устройствами iOS. Просто наследовать контроллер, чтобы иметь то, что вам нужно. Вы можете найти его со всеми инструкциями по следующей ссылке:https://github.com/mikthebig/ios-textfield-scroll
простое решение без добавления уведомления наблюдателя
-(void)setViewMovedUp:(BOOL)movedUp { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; // if you want to slide up the view CGRect rect = self.view.frame; if (movedUp) { // 1. move the view's origin up so that the text field that will be hidden come above the keyboard // 2. increase the size of the view so that the area behind the keyboard is covered up. rect.origin.y -= kOFFSET_FOR_KEYBOARD; rect.size.height += kOFFSET_FOR_KEYBOARD; } else { // revert back to the normal state. rect.origin.y += kOFFSET_FOR_KEYBOARD; rect.size.height -= kOFFSET_FOR_KEYBOARD; } self.view.frame = rect; [UIView commitAnimations]; } -(void)textFieldDidEndEditing:(UITextField *)sender { if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:NO]; } } -(void)textFieldDidBeginEditing:(UITextField *)sender { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:YES]; } }
здесь
#define kOFFSET_FOR_KEYBOARD 80.0
Swift 4
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil) @objc func keyboardWillChange(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.YourView.frame.origin.y+=deltaY },completion: nil) }
на всякий случай, если кто-то ищет решение в Свифт, бросьте это в свой код:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil) } @objc func keyboardWillShow(notification: Notification) { if let userInfo = notification.userInfo { if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue { UIView.animate(withDuration: 0.3) { var alteredFrame = self.view.frame alteredFrame.origin.y = -keyboardSize.height self.view.frame = alteredFrame } } } } @objc func keyboardWillHide(notification: Notification) { UIView.animate(withDuration: 0.3) { var alteredFrame = self.view.frame alteredFrame.origin.y = 0.0 self.view.frame = alteredFrame } }
вот так. Я использовал этот код с UIView, хотя. Вы должны быть в состоянии сделать эти настройки для scrollview.
func addKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func keyboardWillShow(notification: NSNotification) { if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double // if using constraints // bottomViewBottomSpaceConstraint.constant = keyboardSize.height self.view.frame.origin.y -= keyboardSize.height UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() } } } func keyboardWillHide(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double //if using constraint // bottomViewBottomSpaceConstraint.constant = 0 self.view.frame.origin.y = 0 UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() } }
Не забудьте удалить уведомления в правильном месте.
func removeKeyboardNotifications() { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) }
Я только что создал легкий обработчик клавиатуры, чтобы следить за рамкой клавиатуры.
использование:
self.keyboardHandler = [EDKeyboardHandler new]; [self.keyboardHandler listenWithBlock:^(KeyboardInfo *model) { //adjust view positions according to keyboard position here }];
и KeyboardInfo модель имеет следующие свойства:
typedef enum : NSUInteger { KeyboardStatusDidShow, KeyboardStatusWillShow, KeyboardStatusDidHide, KeyboardStatusWillHide, } KeyboardStatus; @interface KeyboardInfo:NSObject @property (nonatomic,readonly) NSTimeInterval animationDuration; @property (nonatomic,readonly) CGRect keyboardFrame; @property (nonatomic,readonly) NSInteger animationCurve; @property (nonatomic,readonly) KeyboardStatus status; @end
Регистрация GitHub проект для деталей и интеграции cocoaPods.
объявите делегат, назначьте ему текстовое поле, а затем включите эти методы.
предполагая, что у вас есть форма входа с текстовыми полями электронной почты и пароля, этот код идеально подходит:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.emailTextField resignFirstResponder]; [self.passwordTextField resignFirstResponder]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { if (self.emailTextField == textField) { [self.passwordTextField becomeFirstResponder]; } else { [self.emailTextField resignFirstResponder]; [self.passwordTextField resignFirstResponder]; } return NO; } - (void)viewWillAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - keyboard movements - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = -0.5f * keyboardSize.height; self.view.frame = f; }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = 0.0f; self.view.frame = f; }]; }
Это можно сделать легко и автоматически если это
textfield
находится в ячейке таблицы (даже когдаtable.scrollable = NO
).Примечание это: положение и размер таблицы должны быть разумными. например:
- если положение y таблицы составляет 100, считая от нижней части представления, то клавиатура высотой 300 будет перекрывать всю таблицу.
- если таблицы
height = 10
иtextfield
в нем должна быть прокручена до 100, когда клавиатура появляется в чтобы быть видимым, тогда это текстовое поле будет вне привязки таблицы.