通用的UITableView键盘resizealgorithm

我已经search了大量的代码,调整表视图,以适应键盘显示和隐藏,但几乎每一个我遇到的单一文章假设表视图是采取其视图控制器的整个视图。 我有一个iPad应用程序的表视图只是在屏幕的一部分。 在这种情况下调整表格视图的正确方法是什么? (所有我上面提到的post中的代码都失败了)

下面的代码可以完成你想要的任何设备和任何布局。 代码是由Sensible TableView框架提供的 (具有复制和使用权限)。

- (void)keyboardWillShow:(NSNotification *)aNotification { if(keyboardShown) return; keyboardShown = YES; // Get the keyboard size UIScrollView *tableView; if([self.tableView.superview isKindOfClass:[UIScrollView class]]) tableView = (UIScrollView *)self.tableView.superview; else tableView = self.tableView; NSDictionary *userInfo = [aNotification userInfo]; NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil]; // Get the keyboard's animation details NSTimeInterval animationDuration; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; UIViewAnimationCurve animationCurve; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; // Determine how much overlap exists between tableView and the keyboard CGRect tableFrame = tableView.frame; CGFloat tableLowerYCoord = tableFrame.origin.y + tableFrame.size.height; keyboardOverlap = tableLowerYCoord - keyboardRect.origin.y; if(self.inputAccessoryView && keyboardOverlap>0) { CGFloat accessoryHeight = self.inputAccessoryView.frame.size.height; keyboardOverlap -= accessoryHeight; tableView.contentInset = UIEdgeInsetsMake(0, 0, accessoryHeight, 0); tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, accessoryHeight, 0); } if(keyboardOverlap < 0) keyboardOverlap = 0; if(keyboardOverlap != 0) { tableFrame.size.height -= keyboardOverlap; NSTimeInterval delay = 0; if(keyboardRect.size.height) { delay = (1 - keyboardOverlap/keyboardRect.size.height)*animationDuration; animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height; } [UIView animateWithDuration:animationDuration delay:delay options:UIViewAnimationOptionBeginFromCurrentState animations:^{ tableView.frame = tableFrame; } completion:^(BOOL finished){ [self tableAnimationEnded:nil finished:nil contextInfo:nil]; }]; } } - (void)keyboardWillHide:(NSNotification *)aNotification { if(!keyboardShown) return; keyboardShown = NO; UIScrollView *tableView; if([self.tableView.superview isKindOfClass:[UIScrollView class]]) tableView = (UIScrollView *)self.tableView.superview; else tableView = self.tableView; if(self.inputAccessoryView) { tableView.contentInset = UIEdgeInsetsZero; tableView.scrollIndicatorInsets = UIEdgeInsetsZero; } if(keyboardOverlap == 0) return; // Get the size & animation details of the keyboard NSDictionary *userInfo = [aNotification userInfo]; NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; CGRect keyboardRect = [tableView.superview convertRect:[aValue CGRectValue] fromView:nil]; NSTimeInterval animationDuration; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; UIViewAnimationCurve animationCurve; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; CGRect tableFrame = tableView.frame; tableFrame.size.height += keyboardOverlap; if(keyboardRect.size.height) animationDuration = animationDuration * keyboardOverlap/keyboardRect.size.height; [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ tableView.frame = tableFrame; } completion:nil]; } - (void) tableAnimationEnded:(NSString*)animationID finished:(NSNumber *)finished contextInfo:(void *)context { // Scroll to the active cell if(self.activeCellIndexPath) { [self.tableView scrollToRowAtIndexPath:self.activeCellIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES]; [self.tableView selectRowAtIndexPath:self.activeCellIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; } } 

笔记:

一个。 上述两种方法已被添加到通知中心使用以下代码:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 

湾 上面使用的ivars已经被声明如下:

 BOOL keyboardShown; CGFloat keyboardOverlap; 

C。 “self.activeCellIndexPath”始终设置为拥有当前活动的UITextField / UITextView的单元格的indexPath。

请享用! 🙂

我发现最简单的解决scheme就是这个(我不喜欢使用子视图这种东西):

注册键盘帧更改通知(idealy寄存器在viewWillAppear:和取消注册viewWillDisappear :):

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil]; 

然后在方法中:

 - (void)keyboardDidChangeFrame:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView]; kbIntersectFrame = CGRectIntersection(self.bounds, kbIntersectFrame); UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0); self.scrollView.contentInset = contentInsets; self.scrollView.scrollIndicatorInsets = contentInsets; } 

或者如果您想在更改contentInset之后摆脱“跳转”:

 - (void)keyboardDidChangeFrame:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect kbIntersectFrame = [window convertRect:CGRectIntersection(window.frame, kbFrame) toView:self.scrollView]; kbIntersectFrame = CGRectIntersection(self.scrollView.bounds, kbIntersectFrame); // get point before contentInset change CGPoint pointBefore = self.scrollView.contentOffset; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbIntersectFrame.size.height, 0.0); self.scrollView.contentInset = contentInsets; self.scrollView.scrollIndicatorInsets = contentInsets; // get point after contentInset change CGPoint pointAfter = self.scrollView.contentOffset; // avoid jump by settings contentOffset self.scrollView.contentOffset = pointBefore; // and now animate smoothly [self.scrollView setContentOffset:pointAfter animated:YES]; } 

简单的解决scheme是将我的扩展UIViewController+Keyboard.swift添加到您的项目,使用一行setupKeyboardNotifcationListenerForScrollView(tableView)它会自动resize。 不需要任何子类,只是一个扩展! 它的开源在SingleLineKeyboardResize

简单的解决scheme – 注册接收键盘通知在init或viewDidLoad与:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 

那么当收到通知的时候,你可以使用键盘的给定矩形来调整你的tableView的框架:

 - (void)keyboardWillShow:(NSNotification *)notification { // Get the size of the keyboard. CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; CGRect newTableFrame = _myTableView.frame; //Here make adjustments to the tableview frame based on the value in keyboard size ... _myTableView.frame = newTableFrame; } - (void)keyboardWillHide:(NSNotification *)notification { //Here change the table frame back to what it originally was. } 

看看这个项目 ,它拖放所以只需要声明TablviewtypesTPKeyboardAvoidingTableView

这里是键盘方法:

 func keyboardControl(notification: NSNotification, isShowing: Bool) { var userInfo = notification.userInfo! let keyboardRect = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey]!.unsignedIntValue let convertedFrame = self.view.convertRect(keyboardRect, fromView: nil) let heightOffset = self.view.bounds.size.height - convertedFrame.origin.y let options = UIViewAnimationOptions(rawValue: UInt(curve) << 16) let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue //your UITableView bottom constrant self.tableViewMarginBottomConstraint.constant = heightOffset var contentInsets = UIEdgeInsetsZero if isShowing { contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardRect.size.height), 0.0) } UIView.animateWithDuration( duration, delay: 0, options: options.union(.LayoutSubviews).union(.BeginFromCurrentState), animations: { self.listTableView.contentInset = contentInsets self.listTableView.scrollIndicatorInsets = contentInsets self.listTableView.scrollBottomToLastRow() self.view.layoutIfNeeded() }, completion: { bool in }) } 

这里是UITableView扩展:

 extension UITableView { func totalRows() -> Int { var i = 0 var rowCount = 0 while i < self.numberOfSections { rowCount += self.numberOfRowsInSection(i) i++ } return rowCount } var lastIndexPath: NSIndexPath { get { return NSIndexPath(forRow: self.totalRows()-1, inSection: 0) } } func scrollBottomToLastRow() { self.scrollToRowAtIndexPath(self.lastIndexPath, atScrollPosition: .Bottom, animated: false) } } 

你可以通过使用IQKeyboardManager来实现你想要的function ,这是一个无代码的库,你只需要将它添加到你的Podfile:pod'IQKeyboardManager'就可以了,即使在显示键盘时也会提交滚动效果UITextField / UITextView不是scrollView / tableView的一部分。