我在StackOverflow上尝试了大部分示例。我也用过Apple。我似乎与他们有的问题是他们没有考虑UITextField在UITableView中。我已经做了很多次,但不是这样。我有一个带有UITextField的自定义UITableViewCell。
在我的UITableView(不是UITableViewController)上,我需要能够避免在UITableView下隐藏UITextField。
我现在有这个:
-(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];
}
这似乎把一堆空白区域推到我的键盘上方。另请注意,我的UITextField上也有一个inputAccessoryView。
哦,我不能使用任何第三方课程。我喜欢TPKeyboardAvoidingScrollView,但我不能使用任何第三方。
答案 0 :(得分:49)
我花了一整天时间试图解决这个问题。我在这里发布了它,然后找到了一个博客链接和一个非常简单的解决方案。它看起来像这样:
-(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;
}
答案 1 :(得分:22)
我尝试了@inturbidus为iOS8发布的链接,但遗憾的是它对我不起作用。经过一番挖掘后,事实证明Apple确实在他们的网站上有示例代码,以便像在UITableViewController中那样自然地完成这项工作。这是Objective-C版本的Apple链接,我也在这里添加了swift版本。
来自Apple的Objective-C链接(滚动到清单5-1): https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
快速调整Objective-C版本
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
}
答案 2 :(得分:7)
感谢@Salman的链接。
请注意,Apple示例在普通视图中用于scrollview
在表视图中,您必须将activeField的Point和Rect转换为表的坐标,因此我更改了函数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)
}
}
如果您的视图有tabBarController,请记住使用tabBar高度而不是UIEdgeInsetsZero重置contentInsets(如果没有,您的最后一行可能会隐藏在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
}
}
答案 3 :(得分:7)
我将 Matt 以及 Salman 的答案混合在一起。 这适用于tableView中的许多文本字段。 Swift 3
基本上是触及textInput的 BOTTOM Y 点。一旦我们有了,我检查键盘是否覆盖textInput,如果这样做,我会改变tableView的contentOffset
首先注册通知。在init中,如果是UIView,或者在viewDidLoad中,如果是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)
然后将触摸的文本字段设置为当前输入
var inputActive: UITextField!
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
inputActive = textInput
return true
}
最后实现通知方法:
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 <= textFieldBottomPoint {
tableView.contentOffset.y = textFieldBottomPoint - keyboardEndPoint
} else {
tableView.contentOffset.y = 0
}
}
}
}
func keyboardWillHide(notification: NSNotification) {
tableView.contentOffset.y = 0
}
很少要添加的东西。 填充是我在案例中添加的额外距离是20分。 同样在我的情况下,UITableView被添加到UIViewController但这也应该在UITableViewController中工作
希望这有帮助!
答案 4 :(得分:2)
我的解决方案(适用于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
}
}
答案 5 :(得分:1)
在常规UIViewController swift 3和Xcode 8.1上的UITableViewCell中将UITextField滚动到键盘上方
1)设置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
}
答案 6 :(得分:1)
这个答案适用于Xamarin iOS用户,但有人可以轻松修改它以使其适用于Swift或Objective C。
解决方案非常简单,在我的情况下完美运行,我需要在屏幕的上半部分显示一个单元格,以便单元格的文本字段位于键盘上方。所以我做的是以下内容:
我用以下方式实现了textField.ShouldBeginEditing:
myTextField.ShouldBeginEditing = textField =>
{
myTableView.ScrollToRow(indexPath, UITableViewScrollPosition.Top, true);
return true;
};
其中:
myTextField 是单元格的文本字段,
myTableView 是表格视图,
indexPath 是表格视图中单元格的索引路径。
正如我之前提到的,这个解决方案在我的案例中完美无缺,所以我想我可以与你们分享它,以防万一它也适合你。快乐的编码:)
答案 7 :(得分:1)
我在@Victor的答案和我拥有的一些代码之间进行了混合。 我创建了一个方便的扩展,可以在许多UITextField中使用。
1.-首先,我们需要 UITextField扩展名来管理键盘通知
extension UITextField {
func keepTextFieldAboveKeyboard(tableView:UITableView) {
var willShowNotification: NSObjectProtocol?
var willHideNotification: NSObjectProtocol?
willShowNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: OperationQueue.main) {(notification) in
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 = self.superview?.convert(self.frame.origin, to: tableView) {
let textFieldBottomPoint = pointInTable.y + self.frame.size.height + 20
// Finally check if the keyboard will cover the textInput
if keyboardEndPoint <= textFieldBottomPoint {
tableView.contentOffset.y = textFieldBottomPoint - keyboardEndPoint
} else {
tableView.contentOffset.y = 0
}
}
}
NotificationCenter.default.removeObserver(willShowNotification!)
}
willHideNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: OperationQueue.main) { (notification) in
tableView.contentOffset.y = 0
NotificationCenter.default.removeObserver(willHideNotification!)
}
}
}
2.-此先前的扩展名应该在 textFieldShouldBeginEditing 内部调用,这样我们也可以为其添加扩展名
extension UITextField : UITextFieldDelegate {
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
guard let tableView = textField.parentView(of: UITableView.self) else { return true };
textField.keepTextFieldAboveKeyboard(tableView:tableView);
return true;
}
}
3 .--最后,您在上一种方法中注意到,我们需要TableView ,其中UITextField的单元格位于该位置。因此,我们可以使用此扩展名(这对其他目的也有用)
extension UIView {
func parentView<T: UIView>(of type: T.Type) -> T? {
guard let view = self.superview else {
return nil
}
return (view as? T) ?? view.parentView(of: T.self)
}
}
4.--最后,在UITextField所在的单元格中,我们只需编写此简单的代码行
textField.delegate = textField;
完全可重用且通用。
答案 8 :(得分:1)
jqgsninimo的解决方案更新为4.2。适用于iOS 12.0。
Swift 4.2
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(with:)), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(with:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardDidShow(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom += keyboardFrame.height
tableView.contentInset = contentInset
tableView.scrollIndicatorInsets = contentInset
}
@objc func keyboardWillHide(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom -= keyboardFrame.height
tableView.contentInset = contentInset
tableView.scrollIndicatorInsets = contentInset
}
答案 9 :(得分:1)
将@Matt Hudsons 的答案转换为 Swift 4.2 并通过委托进行改进:
df <- data.frame("Question" = c("Trust", "Trust", "Trust", "Trust", "Trust", "Evaluation", "Evaluation", "Evaluation", "Evaluation"),
"Value" = c(1, 2, 3, 2, 3, 2, 3, 1, 1, 3)),
"Label" = c("LabelTrust", "LabelTrust", "LabelTrust", "LabelTrust", "LabelTrust", "LabelEvaluation", "LabelEvaluation", "LabelEvaluation", "LabelEvaluation")
在您的 UITableViewCell 中实现 UITextFieldDelegate 并传递 UITextField,如下所示:
func cell(_ cell: UITableViewCell, willStartEditing view: UIView) {
if let inputAccessoryViewHeight = view.inputAccessoryView?.frame.size.height {
var contentOffset = self.tableView.contentOffset
let pointInTable = view.convert(view.frame.origin, to: self.tableView)
contentOffset.y = pointInTable.y - inputAccessoryViewHeight
self.tableView.setContentOffset(contentOffset, animated: true)
}
}
func cell(_ cell: UITableViewCell, willEndEditing view: UIView) {
view.resignFirstResponder()
if let position = self.tableView.indexPath(for: cell) {
self.tableView.scrollToRow(at: position, at: .middle, animated: true)
}
}
答案 10 :(得分:0)
在 swift4 中,我们可以创建 UIViewController 的扩展名。
extension UIViewController {
//MARK: Keyboard user interactions
func handleContainerViewFrameOnKeyboardShowHide(originalContainerFrame: CGRect) {
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: OperationQueue.main) {(notification) in
var info = (notification as NSNotification).userInfo!
let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
var tableViewFrame = originalContainerFrame
tableViewFrame.size.height = originalContainerFrame.size.height - keyboardFrame.size.height
self.view.frame = tableViewFrame
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: OperationQueue.main) { (notification) in
self.view.frame = originalContainerFrame
}
}
}