当键盘出现时,如何滚动UIScrollView?

我的代码有问题。 我在编辑应该被键盘popup窗口隐藏的UITextField时试图移动UIScrollView

我现在正在移动主框架,因为我不知道如何在代码中向上滚动。 所以,我做了一些代码,它工作正常,但是当我编辑一个UItextfield,并切换到另一个UITextField而不按下“返回”button主视图waaayyyyy到遥远的地方。

我做了一个NSLog()与我的variables大小,距离和textFieldRect.origin.y,你可以看到下面。 当我把两个UITextField放在同一个地方(Y起源),我做这个特定的“开关”(没有按回车),我得到了相同的数字,而我的代码工作正常的第一个UITextField编辑,但不是第二次编辑。

看一下这个:

 - (void)textFieldDidBeginEditing:(UITextField *)textField { { int size; CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField]; size = textFieldRect.origin.y + textFieldRect.size.height; if (change == FALSE) { size = size - distance; } if (size < PORTRAIT_KEYBOARD_HEIGHT) { distance = 0; } else if (size > PORTRAIT_KEYBOARD_HEIGHT) { distance = size - PORTRAIT_KEYBOARD_HEIGHT + 5; // +5 px for more visibility } NSLog(@"origin %f", textFieldRect.origin.y); NSLog(@"size %d", size); NSLog(@"distance %d", distance); CGRect viewFrame = self.view.frame; viewFrame.origin.y -= distance; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION]; [self.view setFrame:viewFrame]; [UIView commitAnimations]; change = FALSE; } - (void)textFieldDidEndEditing:(UITextField *)textField { change = TRUE; CGRect viewFrame = self.view.frame; viewFrame.origin.y += distance; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION]; [self.view setFrame:viewFrame]; [UIView commitAnimations]; } 

有任何想法吗 ?

Apple推荐的方法是更改UIScrollViewcontentInset 。 这是一个非常优雅的解决scheme,因为您不必乱用contentSize 。 下面的代码是从键盘编程指南中复制的,在这里解释了这个问题的处理。 你应该看看它。

 // Call this method somewhere in your view controller setup code. - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; } // Called when the UIKeyboardDidShowNotification is sent. - (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; // If active text field is hidden by keyboard, scroll it so it's visible // Your application might not need or want this behavior. CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) { CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height); [scrollView setContentOffset:scrollPoint animated:YES]; } } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; } 

我刚刚在Xcode 7(testing版6)上用Swift 2.0 for iOS9实现了这一点,在这里工作正常。

 override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) registerKeyboardNotifications() } func registerKeyboardNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil) } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } func keyboardWillShow(notification: NSNotification) { let userInfo: NSDictionary = notification.userInfo! let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets var viewRect = view.frame viewRect.size.height -= keyboardSize.height if CGRectContainsPoint(viewRect, textField.frame.origin) { let scrollPoint = CGPointMake(0, textField.frame.origin.y - keyboardSize.height) scrollView.setContentOffset(scrollPoint, animated: true) } } func keyboardWillHide(notification: NSNotification) { scrollView.contentInset = UIEdgeInsetsZero scrollView.scrollIndicatorInsets = UIEdgeInsetsZero } 

编辑Swift 3

看起来像你只需要设置与Swift 3的contentInsetscrollIndicatorInset ,滚动/ contentOffset自动完成..

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) registerKeyboardNotifications() } func registerKeyboardNotifications() { 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) } deinit { NotificationCenter.default.removeObserver(self) } func keyboardWillShow(notification: NSNotification) { let userInfo: NSDictionary = notification.userInfo! as NSDictionary let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue let keyboardSize = keyboardInfo.cgRectValue.size let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets } func keyboardWillHide(notification: NSNotification) { scrollView.contentInset = .zero scrollView.scrollIndicatorInsets = .zero } 

这里的所有答案似乎都忘记了景观的可能性。 如果您想在设备旋转到横向视图时使用此function,那么您将遇到问题。

这里的诀窍是虽然视图知道方向,但键盘不是。 这意味着在景观中,键盘的宽度实际上是其高度,反之亦然。

要修改苹果build议更改内容插入的方式,并获得它支持横向方向,我会build议使用以下内容:

 // Call this method somewhere in your view controller setup code. - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; } // Called when the UIKeyboardDidShowNotification is sent. - (void)keyboardWasShown:(NSNotification*)aNotification { UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) { CGSize origKeySize = keyboardSize; keyboardSize.height = origKeySize.width; keyboardSize.width = origKeySize.height; } UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0); scroller.contentInset = contentInsets; scroller.scrollIndicatorInsets = contentInsets; // If active text field is hidden by keyboard, scroll it so it's visible // Your application might not need or want this behavior. CGRect rect = scroller.frame; rect.size.height -= keyboardSize.height; NSLog(@"Rect Size Height: %f", rect.size.height); if (!CGRectContainsPoint(rect, activeField.frame.origin)) { CGPoint point = CGPointMake(0, activeField.frame.origin.y - keyboardSize.height); NSLog(@"Point Height: %f", point.y); [scroller setContentOffset:point animated:YES]; } } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; } 

这里要注意的部分是:

 UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) { CGSize origKeySize = keyboardSize; keyboardSize.height = origKeySize.width; keyboardSize.width = origKeySize.height; } 

什么是检测设备在哪个方向。如果是横向,它将“交换”keyboardSizevariables的宽度和高度值,以确保在每个方向上使用正确的值。

对于这个东西,不需要很多编码,就像下面的代码一样简单:

你的所有文字在UIScrollview从笔尖像这个图像: –

在这里输入图像描述

YourViewController.h

 @interface cntrInquiryViewController : UIViewController<UIScrollViewDelegate,UITextFieldDelegate> { IBOutlet UITextField *txtName; IBOutlet UITextField *txtEmail; IBOutlet UIScrollView *srcScrollView; } @end 

从nib连接IBOutlet,并连接来自NIB的UItextfiled和scrollview委托的每个委托

 -(void)viewWillAppear:(BOOL)animated { srcScrollView.contentSize = CGSizeMake(320, 500); [super viewWillAppear:YES]; } -(void)textFieldDidBeginEditing:(FMTextField *)textField { [srcScrollView setContentOffset:CGPointMake(0,textField.center.y-140) animated:YES];//you can set your y cordinate as your req also } -(BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; [srcScrollView setContentOffset:CGPointMake(0,0) animated:YES]; return YES; } 

注意如果文本提交代表没有连接,那么没有一个方法工作,请确保所有iBOulate和代表连接正确

苹果的build议logging在Swift +在iOS中使用UIScrollView与自动布局(基于以下链接: 链接1 , 链接2 , 链接3 ):

 import UIKit class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet var t1: UITextField! @IBOutlet var t2: UITextField! @IBOutlet var t3: UITextField! @IBOutlet var t4: UITextField! @IBOutlet var srcScrollView: UIScrollView! @IBOutlet var contentView: UIView! var contentViewCoordinates: CGPoint! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. /* Constraints on content view */ let leftConstraint = NSLayoutConstraint(item:self.contentView, attribute:NSLayoutAttribute.Leading, relatedBy:NSLayoutRelation.Equal, toItem:self.view, attribute:NSLayoutAttribute.Left, multiplier:1.0, constant:0) self.view.addConstraint(leftConstraint) let rightConstraint = NSLayoutConstraint(item:self.contentView, attribute:NSLayoutAttribute.Trailing, relatedBy:NSLayoutRelation.Equal, toItem:self.view, attribute:NSLayoutAttribute.Right, multiplier:1.0, constant:0) self.view.addConstraint(rightConstraint) /* Tap gesture */ let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideKeyboard") // prevents the scroll view from swallowing up the touch event of child buttons tapGesture.cancelsTouchesInView = false srcScrollView.addGestureRecognizer(tapGesture) /* Save content view coordinates */ contentViewCoordinates = contentView.frame.origin } func hideKeyboard() { t1.resignFirstResponder() t2.resignFirstResponder() t3.resignFirstResponder() t4.resignFirstResponder() } var activeField: UITextField? func textFieldDidBeginEditing(textField: UITextField) { activeField = textField } func textFieldDidEndEditing(textField: UITextField) { activeField = nil } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) let center = NSNotificationCenter.defaultCenter() center.addObserver(self, selector: "keyboardOnScreen:", name: UIKeyboardDidShowNotification, object: nil) center.addObserver(self, selector: "keyboardOffScreen:", name: UIKeyboardDidHideNotification, object: nil) } func keyboardOnScreen(notification: NSNotification){ // Retrieve the size and top margin (inset is the fancy word used by Apple) // of the keyboard displayed. let info: NSDictionary = notification.userInfo! let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize!.height, 0.0) srcScrollView.contentInset = contentInsets srcScrollView.scrollIndicatorInsets = contentInsets var aRect: CGRect = self.view.frame aRect.size.height -= kbSize!.height //you may not need to scroll, see if the active field is already visible if (CGRectContainsPoint(aRect, activeField!.frame.origin) == false) { let scrollPoint:CGPoint = CGPointMake(0.0, activeField!.frame.origin.y - kbSize!.height) srcScrollView.setContentOffset(scrollPoint, animated: true) } } // func keyboardOnScreen(aNotification: NSNotification) { // let info: NSDictionary = aNotification.userInfo! // let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size // // var bkgndRect: CGRect! = activeField?.superview?.frame // // bkgndRect.size.height += kbSize!.height // // activeField?.superview?.frame = bkgndRect // // srcScrollView.setContentOffset(CGPointMake(0.0, activeField!.frame.origin.y - kbSize!.height), animated: true) // } func keyboardOffScreen(notification: NSNotification){ let contentInsets:UIEdgeInsets = UIEdgeInsetsZero srcScrollView.contentInset = contentInsets srcScrollView.scrollIndicatorInsets = contentInsets self.srcScrollView.setContentOffset(CGPointMake(0, -self.view.frame.origin.y/2), animated: true) } } 

在Apple代码中唯一更新的是keyboardWillBeHidden:方法,以提供平滑过渡。

 // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; [UIView animateWithDuration:0.4 animations:^{ self.scrollView.contentInset = contentInsets; }]; self.scrollView.scrollIndicatorInsets = contentInsets; } 

我发现上面的答案已经过时了。 滚动时也不完美。

这是一个迅速的版本。

它将滚动到textField的正下方,没有多余的空间。 它会恢复到它第一次出现的样子。

 //add observer override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidHide(_:)), name: UIKeyboardDidHideNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { let userInfo: NSDictionary = notification.userInfo! let keyboardSize = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)!.CGRectValue.size let difference = keyboardSize.height - (self.view.frame.height - inputTextField.frame.origin.y - inputTextField.frame.size.height) if difference > 0 { var contentInset:UIEdgeInsets = self.scrollView.contentInset contentInset.bottom = difference self.scrollView.contentInset = contentInset let scrollPoint = CGPointMake(0, difference) self.scrollView.setContentOffset(scrollPoint, animated: true) } } func keyboardDidHide(notification: NSNotification) { let contentInset:UIEdgeInsets = UIEdgeInsetsZero self.scrollView.contentInset = contentInset } //remove observer deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } 

这里是一个Swift 3兼容的答案,这也将在导航控制器内的视图控制器 – 因为他们将更改滚动视图contentInset.top属性。

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.registerKeyboardNotifications() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.unregisterKeyboardNotifications() } func registerKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardDidShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func unregisterKeyboardNotifications() { NotificationCenter.default.removeObserver(self) } func keyboardDidShow(notification: NSNotification) { let userInfo: NSDictionary = notification.userInfo! as NSDictionary let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue let keyboardSize = keyboardInfo.cgRectValue.size // Get the existing contentInset for the scrollView and set the bottom property to be the height of the keyboard var contentInset = self.scrollView.contentInset contentInset.bottom = keyboardSize.height self.scrollView.contentInset = contentInset self.scrollView.scrollIndicatorInsets = contentInset } func keyboardWillHide(notification: NSNotification) { var contentInset = self.scrollView.contentInset contentInset.bottom = 0 self.scrollView.contentInset = contentInset self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero } 

这是我一直在使用的。 这很简单,它运作良好。

 #pragma mark - Scrolling -(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]; } -(void)scrollToY:(float)y { [UIView animateWithDuration:0.3f animations:^{ [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; self.view.transform = CGAffineTransformMakeTranslation(0, y); }]; } 

使用UITextField委托调用textFieldDidBeginEditing:向上移动视图,并添加通知观察者以在隐藏键盘时将视图恢复到正常状态:

 -(void)textFieldDidBeginEditing:(UITextField *)textField { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; if (self.view.frame.origin.y == 0) [self scrollToY:-90.0]; // y can be changed to your liking } -(void)keyboardWillHide:(NSNotification*)note { [self scrollToY:0]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 

这是Swift改进的最终代码

  //MARK: UITextFieldDelegate func textFieldDidBeginEditing(textField: UITextField!) { //delegate method self.textField = textField } func textFieldShouldReturn(textField: UITextField!) -> Bool { //delegate method textField.resignFirstResponder() return true } //MARK: Keyboard handling override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) unregisterKeyboardNotifications() } func registerKeyboardNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil) } func unregisterKeyboardNotifications() { NSNotificationCenter.defaultCenter().removeObserver(self) } func keyboardDidShow(notification: NSNotification) { let userInfo: NSDictionary = notification.userInfo! let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets var viewRect = self.view.frame viewRect.size.height -= keyboardSize.height let relativeFieldFrame: CGRect = textField.convertRect(textField.frame, toView: self.view) if CGRectContainsPoint(viewRect, relativeFieldFrame.origin) { let scrollPoint = CGPointMake(0, relativeFieldFrame.origin.y - keyboardSize.height) scrollView.setContentOffset(scrollPoint, animated: true) } } func keyboardWillHide(notification: NSNotification) { scrollView.contentInset = UIEdgeInsetsZero scrollView.scrollIndicatorInsets = UIEdgeInsetsZero } 

我会这样做。 这是很多的代码,但它确保了,当前焦点的textField在'可用空间'中是垂直居中的:

 - (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]; } - (void)keyboardWillShow:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; NSValue *keyBoardEndFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey]; CGSize keyboardSize = [keyBoardEndFrame CGRectValue].size; self.keyboardSize = keyboardSize; [self adjustScrollViewOffsetToCenterTextField:self.currentTextField]; } - (void)keyboardWillHide:(NSNotification *)notification { self.keyboardSize = CGSizeZero; } - (IBAction)textFieldGotFocus:(UITextField *)sender { sender.inputAccessoryView = self.keyboardAccessoryView; self.currentTextField = sender; [self adjustScrollViewOffsetToCenterTextField:sender]; } - (void)adjustScrollViewOffsetToCenterTextField:(UITextField *)textField { CGRect textFieldFrame = textField.frame; float keyboardHeight = MIN(self.keyboardSize.width, self.keyboardSize.height); float visibleScrollViewHeight = self.scrollView.frame.size.height - keyboardHeight; float offsetInScrollViewCoords = (visibleScrollViewHeight / 2) - (textFieldFrame.size.height / 2); float scrollViewOffset = textFieldFrame.origin.y - offsetInScrollViewCoords; [UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, scrollViewOffset); }completion:NULL]; } you'll need these two properties in your @interface... @property (nonatomic, assign) CGSize keyboardSize; @property (nonatomic, strong) UITextField *currentTextField; 

请注意, - (IBAction)textFieldGotFocus:操作已连接到每个textField的DidBeginEditing状态。

从键盘通知中获得animation持续时间,并将其用于滚动视图animation,而不是一个固定的值,会更好一些,但请告诉我,这对我来说已经足够了;)

你实际上不需要一个UIScrollView来做到这一点。 我使用这个代码,它适用于我:

 -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { if (textField==_myTextField) { [self keyBoardAppeared]; } return true; } -(void)textFieldDidEndEditing:(UITextField *)textField { if (textField==_myTextField) { [self keyBoardDisappeared]; } } -(void) keyBoardAppeared { CGRect frame = self.view.frame; [UIView animateWithDuration:0.3 delay:0 options: UIViewAnimationCurveEaseOut animations:^{ self.view.frame = CGRectMake(frame.origin.x, frame.origin.y-215, frame.size.width, frame.size.height); } completion:^(BOOL finished){ }]; } -(void) keyBoardDisappeared { CGRect frame = self.view.frame; [UIView animateWithDuration:0.3 delay:0 options: UIViewAnimationCurveEaseOut animations:^{ self.view.frame = CGRectMake(frame.origin.x, frame.origin.y+215, frame.size.width, frame.size.height); } completion:^(BOOL finished){ }]; } 

你可以使用UIScrollView属性contentOffset进行滚动,例如,

 CGPoint offset = scrollview.contentOffset; offset.y -= KEYBOARD_HEIGHT + 5; scrollview.contentOffset = offset; 

还有一种做animation滚动的方法。

至于你的第二个编辑不能正确滚动的原因,可能是因为你似乎认为每次编辑开始时都会出现一个新的键盘。 你可以尝试检查你是否已经调整了“键盘”的可见位置(同样在恢复之前检查键盘可见性)。

更好的解决scheme可能是监听键盘通知,例如:

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

我知道这是一个古老的问题,但我认为这可能会帮助别人。 我想要一些更容易实现的应用程序,所以我为此做了一个类。 你可以在这里下载它: https : //github.com/sdernley/iOSTextFieldHandler

就像设置所有的UITextFields有一个自我委托一样简单

 textfieldname.delegate = self; 

然后用您的scrollView和提交button的名称添加到您的视图控制器

 - (void)textFieldDidBeginEditing:(UITextField *)textField { [iOSTextFieldHandler TextboxKeyboardMover:containingScrollView tf:textField btn:btnSubmit]; } 

以下是我的解决scheme(5步)

第1步:添加一个观察者来捕获哪个UITEXTFIELD或UITEXTVIEW ShoudBeginEditing(哪里对象是inited或ViewDidLoad。

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateActiveField:) name:@"UPDATE_ACTIVE_FIELD" object:nil]; 

第二步:在使用UITEXTFIELD或UITEXTVIEW的对象进行编辑时发布通知

 -(BOOL)textViewShouldBeginEditing:(UITextView *)textView { [[NSNotificationCenter defaultCenter] postNotificationName:@"UPDATE_ACTIVE_FIELD" object:textView]; return YES; } 

Step3:(Step1 calles)分配当前的UITEXTFIELD或UITEXTVIEW的方法

 -(void) updateActiveField: (id) sender { activeField = [sender object]; } 

第四步:添加键盘观察者UIKeyboardWillShowNotification(与第一步相同的地方)

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; 

和方法:

 // Called when the UIKeyboardDidShowNotification is sent. - (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); _currentEdgeInsets = self.layoutPanel.contentInset; // store current insets to restore them later self.layoutPanel.contentInset = contentInsets; self.layoutPanel.scrollIndicatorInsets = contentInsets; // If active text field is hidden by keyboard, scroll it so it's visible CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; UIWindow *window = [[UIApplication sharedApplication] keyWindow]; CGPoint p = [activeField convertPoint:activeField.bounds.origin toView:window]; if (!CGRectContainsPoint(aRect, p) ) { CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y +kbSize.height); [self.layoutPanel setContentOffset:scrollPoint animated:YES]; self.layoutPanel.scrollEnabled = NO; } } 

第五步:添加键盘观察者UIKeyboardWillHideNotification(与第一步相同的地方)

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

和方法:

 // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { self.layoutPanel.contentInset = _currentEdgeInsets; self.layoutPanel.scrollIndicatorInsets = _currentEdgeInsets; self.layoutPanel.scrollEnabled = YES; } 

记得要删除观察者!

如果您不想计算太多,请使用以下扩展名:

 func scrollSubviewToBeVisible(subview: UIView, animated: Bool) { let visibleFrame = UIEdgeInsetsInsetRect(self.bounds, self.contentInset) let subviewFrame = subview.convertRect(subview.bounds, toView: self) if (!CGRectContainsRect(visibleFrame, subviewFrame)) { self.scrollRectToVisible(subviewFrame, animated: animated) } } 

也许你想保持你的UITextField始终可见:

 func textViewDidChange(textView: UITextView) { self.scrollView?.scrollSubviewToBeVisible(textView, animated: false) } 

我用这个答案由Sudheer Palchuri提供https://stackoverflow.com/users/2873919/sudheer-palchuri https://stackoverflow.com/a/32583809/6193496

在ViewDidLoad中,注册通知:

 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillShow(_:)), name:UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil) 

添加下面的观察者方法,当键盘出现时自动滚动。

 func textFieldShouldReturn(textField: UITextField) -> Bool { textField.resignFirstResponder() return true } func keyboardWillShow(notification:NSNotification){ var userInfo = notification.userInfo! var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue() keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil) var contentInset:UIEdgeInsets = self.scrollView.contentInset contentInset.bottom = keyboardFrame.size.height self.scrollView.contentInset = contentInset } func keyboardWillHide(notification:NSNotification){ var contentInset:UIEdgeInsets = UIEdgeInsetsZero self.scrollView.contentInset = contentInset } 

我的解决scheme有4步:
– 步骤1:function在键盘出现时进行监听

 - (void)keyboardWasShown:(NSNotification *)notification { // Get the size of the keyboard. CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; //top: 64 for navigation bar, 0 for without navigation UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, keyboardSize.height, 0); _scrollView.contentInset = contentInsets; _scrollView.scrollIndicatorInsets = contentInsets; } 

– 第2步:该function在键盘消失时进行监听

 - (void)keyboardWillHide:(NSNotification *)notification { //top: 64 for navigatiob bar UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, 0, 0); [_editScrollView setContentInset: contentInsets]; [_editScrollView setScrollIndicatorInsets: contentInsets]; } 

– 步骤3:将这些function添加到通知中心:

 - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } 

– 第4步:删除视图控制器消散时的监听

 - (void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 

在Swift 3中试试这个代码:

 override func viewDidAppear(_ animated: Bool) { setupViewResizerOnKeyboardShown() } func setupViewResizerOnKeyboardShown() { NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShowForResizing), name: Notification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHideForResizing), name: Notification.Name.UIKeyboardWillHide, object: nil) } func keyboardWillShowForResizing(notification: Notification) { if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue, let window = self.view.window?.frame { // We're not just minusing the kb height from the view height because // the view could already have been resized for the keyboard before self.view.frame = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: window.origin.y + window.height - keyboardSize.height) } else { debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.") } } func keyboardWillHideForResizing(notification: Notification) { if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { let viewHeight = self.view.frame.height self.view.frame = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: viewHeight) //viewHeight + keyboardSize.height } else { debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.") } } deinit { NotificationCenter.default.removeObserver(self) }