Перемещение 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; @endUIView + 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, когда клавиатура появляется в чтобы быть видимым, тогда это текстовое поле будет вне привязки таблицы.
