在iOS中出现键盘时向上移动UIView
我有一个UIView,它不在UIScrollView里面。 我想在键盘出现时向上移动视图。 在我尝试使用这个解决scheme之前: 当键盘出现时,如何使UITextField向上移动? 。 这工作正常。 但是,在将数据插入到文本框之后,它将我带到另一个视图,当我回到此页面时,它只是跳跃,而我看不到我的文本字段。 有没有更好的解决scheme,对于这个问题?
提前致谢!
使用以下代码显示和隐藏keyBoard
//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 ie 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上写了一个小类,它pipe理着临时滚动的东西,而不需要把整个东西包装到一个UIScrollView中。 我在这里使用动词“滚动”可能不是很理想,因为它可能会让你觉得有一个滚动视图,并没有 – 我们只是animation的UIView(或UIView子类)的位置。
有一些embedded在这个适合我的forms和布局,可能不适合你的魔法数字,所以我鼓励调整,以适应您的具体需求。
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.m:
#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]; }
…pipe他呢。 该类别为您提供了三种很好的方式来调整视图的位置。
Swift 2.0 + 3.0
使用扩展名:
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) } }
使用:
textField.bindToKeyboard()
结果:
重要
更好的用户子类的UIView
也添加deinit方法来使用removeObserver()
我发现Duncs的答案非常有用,下面你可以find我自己的(重构)版本:
主要变化
- 现在dynamic获取键盘大小 ,而不是硬编码值
- 提取UIViewanimation到它自己的方法,以防止重复的代码
- 允许的持续时间传递给方法,而不是硬编码
- (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; }]; }
基于Daniel Krom的解决scheme。 这是3.0版本的swift 。 与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
添加bindToKeyboard
函数,如:
override func viewDidLoad() { super.viewDidLoad() view.bindToKeyboard() }
并在deinit中添加unbindFromKeyboard
函数:
deinit { view.unbindFromKeyboard() }
对于与KeyBoard相关的所有问题,只需使用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; }
我已经实现了一个自定义控制器,它可以dynamic计算键盘的大小,即使在设备旋转的时候也可以滚动textFields。 适用于所有iOS设备。 只需简单地inheritance控制器即可获得所需的内容。 您可以在以下链接中find所有说明: https : //github.com/mikthebig/ios-textfield-scroll
简单的解决scheme,无需添加观察员通知
-(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
基于Dunc的答案,但用Autolayout在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() } }
如果该文本字段位于表格单元格中(即使在table.scrollable = NO时),也可以轻松自动完成。
注意 :表格的位置和大小必须合理。 例如:
- 如果表格的y位置从视图底部开始计数为100,那么300高度键盘将与整个表格重叠。
- 如果表格的高度= 10,并且出现键盘时,其中的文本字段必须向上滚动100以便可见,那么该文本字段将不在表格的边界内。
//声明一个委托,将你的textField分配给委托,然后包含这些方法
//假设你有一个电子邮件和密码文本字段的login表单,这个代码将完全适合
-(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; }]; }
我刚刚创build了一个轻量级键盘处理程序来跟随键盘框架
用法:
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集成。
你是SWIFT情人吗?
干得好。 不过,我已经使用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) }
基于苹果文本编程指南。
示例项目