可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have tried most of the examples here on StackOverflow. I also used Apple's. The problem I seem to have with them is that they don't account for the UITextField being in a UITableView. I've done this many times, but not in this way. I have a custom UITableViewCell with a UITextField in it.
On my UITableView (which is NOT a UITableViewController), I need to be able to avoid hiding the UITextField under the UITableView.
I have this as of now:
-(void)viewDidLoad { .... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; .... } - (void)scrollToRectOfTextField { UITableViewCell *cell = (UITableViewCell*)[self.activeTextField superview]; CGRect r = CGRectMake(self.activeTextField.frame.origin.x, cell.frame.origin.y+self.activeTextField.frame.origin.y, self.activeTextField.frame.size.width, self.activeTextField.frame.size.height); [self.tableView scrollRectToVisible:r animated:YES]; } - (void)keyboardDidShow:(NSNotification *)notification { if (UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPhone) { NSDictionary *userInfo = [notification userInfo]; CGSize size = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; NSLog(@"TableView: %@", NSStringFromCGRect(self.tableView.frame)); CGRect newTableViewFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.tableView.frame.size.height - size.height); self.tableView.frame = newTableViewFrame; NSLog(@"New TableView: %@", NSStringFromCGRect(self.tableView.frame)); self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height-size.height); } } - (void)keyboardWillHide:(NSNotification *)notification { NSDictionary *userInfo = [notification userInfo]; CGSize size = [[userInfo objectForKey: UIKeyboardFrameEndUserInfoKey] CGRectValue].size; self.tableView.frame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.tableView.frame.size.height + size.height); NSLog(@"%@", NSStringFromCGRect(self.tableView.frame)); } -(void)textFieldDidBeginEditing { [self scrollToRectOfTextField]; }
This seems to push a bunch of white space up past my keyboard. Please also note that I have an inputAccessoryView on my UITextField as well.
Oh, and I cannot use any third party classes. I love TPKeyboardAvoidingScrollView, but I cannot use anything third party.
回答1:
I spent all day trying to figure this out. I posted it here, then found a blog link and an incredibly simple solution. It looks like this:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { CGPoint pointInTable = [textField.superview convertPoint:textField.frame.origin toView:self.tableView]; CGPoint contentOffset = self.tableView.contentOffset; contentOffset.y = (pointInTable.y - textField.inputAccessoryView.frame.size.height); NSLog(@"contentOffset is: %@", NSStringFromCGPoint(contentOffset)); [self.tableView setContentOffset:contentOffset animated:YES]; return YES; } -(BOOL)textFieldShouldEndEditing:(UITextField *)textField { [textField resignFirstResponder]; if ([textField.superview.superview isKindOfClass:[UITableViewCell class]]) { UITableViewCell *cell = (UITableViewCell*)textField.superview.superview; NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:TRUE]; } return YES; }
Check this for iOS 8
回答2:
I tried the link that @inturbidus posted for iOS8 but unfortunately it did not work for me. After a bit of digging, it turns out that Apple does have sample code on their website to make this work naturally as they do in the UITableViewController. Here's the Apple link for the Objective-C version and I'm also adding the swift version here.
Objective-C link from Apple (Scroll to listing 5-1): https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Swift adaptation of the Objective-C Version
var activeField: UITextField? func textFieldDidBeginEditing(textField: UITextField) { self.activeField = textField } func textFieldDidEndEditing(textField: UITextField) { self.activeField = nil } func registerForKeyboardNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil) } func keyboardWasShown(aNotification: NSNotification) { let info = aNotification.userInfo as! [String: AnyObject], kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue().size, contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0) self.tableView.contentInset = contentInsets self.tableView.scrollIndicatorInsets = contentInsets // If active text field is hidden by keyboard, scroll it so it's visible // Your app might not need or want this behavior. var aRect = self.view.frame aRect.size.height -= kbSize.height if !CGRectContainsPoint(aRect, activeField!.frame.origin) { self.tableView.scrollRectToVisible(activeField!.frame, animated: true) } } func keyboardWillBeHidden(aNotification: NSNotification) { let contentInsets = UIEdgeInsetsZero self.tableView.contentInset = contentInsets self.tableView.scrollIndicatorInsets = contentInsets }
回答3:
Thank @Salman for the link.
Just notice that Apple example is used for scrollview in normal view.
In table view you must convert Point and Rect of activeField to table's coordinate, so I change some lines in function keyboardWasShown:
func keyboardWasShown(aNotification: NSNotification) { let info = aNotification.userInfo as! [String: AnyObject], kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue().size, contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0) self.tableBasket.contentInset = contentInsets self.tableBasket.scrollIndicatorInsets = contentInsets var aRect = self.view.frame aRect.size.height -= kbSize.height let pointInTable = activeField!.superview!.convertPoint(activeField!.frame.origin, toView: tableView) let rectInTable = activeField!.superview!.convertRect(activeField!.frame, toView: tableView) if !CGRectContainsPoint(aRect, pointInTable) { self.tableView.scrollRectToVisible(rectInTable, animated: true) } }
And if your view has tabBarController, remember to reset contentInsets with tabBar height instead of UIEdgeInsetsZero (if not, your last bottom rows maybe hiden under tabBar):
func keyboardWillBeHidden(aNotification: NSNotification) { //UIEdgeInsetsZero is used in view without tabBar //let contentInsets = UIEdgeInsetsZero let tabBarHeight = self.tabBarController!.tabBar.frame.height let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: tabBarHeight, right: 0) self.tableView.contentInset = contentInsets self.tableView.scrollIndicatorInsets = contentInsets } }
回答4:
I made a mix with the answers of Matt and also Salman. This works for many textfields in a tableView. Swift 3
Basically is get the BOTTOM Y point of the textInput touched. Once we have that I check if the keyboard cover the textInput and if do it I would change the contentOffset of the tableView
First register to the notifications. In the init if is a UIView or in viewDidLoad if is a UIViewController:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
Then set up the textfield touched as current input
var inputActive: UITextField! func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { inputActive = textInput return true }
Finally implement the notifications method:
func keyboardWillShow(notification: NSNotification) { var userInfo = notification.userInfo! if let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { // Get my height size let myheight = tableView.frame.height // Get the top Y point where the keyboard will finish on the view let keyboardEndPoint = myheight - keyboardFrame.height // Get the the bottom Y point of the textInput and transform it to the currentView coordinates. if let pointInTable = inputActive.superview?.convert(inputActive.frame.origin, to: tableView) { let textFieldBottomPoint = pointInTable.y + inputActive.frame.size.height + 20 // Finally check if the keyboard will cover the textInput if keyboardEndPoint
Few things to add. The padding is some extra distance that I add in my case was 20 points. Also in my case the UITableView was added to a UIViewController but this should work also in a UITableViewController
Hope this helps!
回答5:
My solution (worked on Xcode 8.3.3, Swift 3, iOS 10.3.1):
class MyTableViewController: UITableViewController { override func viewWillAppear(_ animated: Bool) { NotificationCenter.default.addObserver(self, selector: #selector(actionKeyboardDidShow(with:)), name: .UIKeyboardDidShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(actionKeyboardWillHide(with:)), name: .UIKeyboardWillHide, object: nil) } override func viewDidDisappear(_ animated: Bool) { NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil) } @objc private func actionKeyboardDidShow(with notification: Notification) { guard let userInfo = notification.userInfo as? [String: AnyObject], let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue else { return } var contentInset = self.tableView.contentInset contentInset.bottom += keyboardFrame.height self.tableView.contentInset = contentInset self.tableView.scrollIndicatorInsets = contentInset } @objc private func actionKeyboardWillHide(with notification: Notification) { guard let userInfo = notification.userInfo as? [String: AnyObject], let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue else { return } var contentInset = self.tableView.contentInset contentInset.bottom -= keyboardFrame.height self.tableView.contentInset = contentInset self.tableView.scrollIndicatorInsets = contentInset } }
回答6:
Scroll UITextField above Keyboard in a UITableViewCell on a regular UIViewController swift 3 and Xcode 8.1
1) set Delegate = UITextFieldDelegate
override func viewWillAppear(_ animated: Bool) { NotificationCenter.default.addObserver(self, selector: #selector(DayViewController.keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil); NotificationCenter.default.addObserver(self, selector: #selector(DayViewController.keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil); } func textFieldDidBeginEditing(_ textField: UITextField) { self.activeField = textField } func textFieldDidEndEditing(_ textField: UITextField) { self.activeField = nil } //MARK: - Keyboard Show and Hide Methods func keyboardWillShow(notification: NSNotification) { let info = notification.userInfo! as! [String: AnyObject], kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue.size, contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0) self.FourthTblMainTableView.contentInset = contentInsets self.FourthTblMainTableView.scrollIndicatorInsets = contentInsets var aRect = self.FourthTblMainTableView.frame aRect.size.height -= kbSize.height } func keyboardWillHide(notification: NSNotification) { let contentInsets = UIEdgeInsets.zero self.FourthTblMainTableView.contentInset = contentInsets self.FourthTblMainTableView.scrollIndicatorInsets = contentInsets }
回答7:
This answer is for Xamarin iOS users, however someone can easily modify it to make it work with Swift or Objective C.
The solution is very simple and has worked perfectly in my case where I needed a cell to appear on the top half of the screen in order for the cell's textfield to be above keyboard. So what I did is the following:
I implemented textField.ShouldBeginEditing the following way:
myTextField.ShouldBeginEditing = textField => { myTableView.ScrollToRow(indexPath, UITableViewScrollPosition.Top, true); return true; };
Where:
myTextField is the cell's text field,
myTableView is the table view,
indexPath is the cell's index path within the table view.
As I previously mentioned, this solution works perfectly in my case so I thought I could share it with you guys in case it works for you as well. Happy coding :)