只有在键盘覆盖input字段时才能移动视图

我正在尝试为iPhone构build一个input屏幕。 屏幕上有许多input字段。 他们大多数在屏幕的顶部,但两个领域是在底部。 当用户尝试编辑屏幕底部的文本时,键盘将popup,并将覆盖屏幕。 当发生这种情况时,我find了一个简单的解决scheme来移动屏幕,但结果是屏幕总是向上移动,而当用户尝试编辑这些屏幕时,屏幕顶部的字段不可用。

有没有办法让屏幕在底部字段被编辑时才移动?

我使用了我在这里find的这个代码:

override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil); NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil); } func keyboardWillShow(sender: NSNotification) { self.view.frame.origin.y -= 150 } func keyboardWillHide(sender: NSNotification) { self.view.frame.origin.y += 150 } 

Apple在本文档中已经很好地解释了您的问题。 这个页面的示例代码(在Listing 4-1 )正好满足你的需要:只有在当前的编辑应该在键盘下时,才会滚动你的视图。 你只需要把你需要的控件放在scrollViiew中。 唯一的问题是,这是Objective-C,我认为你需要它在Swift .. so..here..here:

声明一个variables

 var activeField: UITextField? 

然后添加这些方法

  func registerForKeyboardNotifications() { //Adding notifies on keyboard appearing NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil) } func deregisterFromKeyboardNotifications() { //Removing notifies on keyboard appearing NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) } func keyboardWasShown(notification: NSNotification) { //Need to calculate keyboard exact size due to Apple suggestions self.scrollView.scrollEnabled = true var info : NSDictionary = notification.userInfo! var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeFieldPresent = activeField { if (!CGRectContainsPoint(aRect, activeField!.frame.origin)) { self.scrollView.scrollRectToVisible(activeField!.frame, animated: true) } } } func keyboardWillBeHidden(notification: NSNotification) { //Once keyboard disappears, restore original positions var info : NSDictionary = notification.userInfo! var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets self.view.endEditing(true) self.scrollView.scrollEnabled = false } func textFieldDidBeginEditing(textField: UITextField!) { activeField = textField } func textFieldDidEndEditing(textField: UITextField!) { activeField = nil } 

一定要声明你的ViewController为UITextFieldDelegate并在你的初始化方法中设置正确的委托:例如:

 self.you_text_field.delegate = self 

记得在退出时在viewInit和deregisterFromKeyboardNotifications上调用registerForKeyboardNotifications

编辑/更新:Swift 3.0语法

 func registerForKeyboardNotifications(){ //Adding notifies on keyboard appearing NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func deregisterFromKeyboardNotifications(){ //Removing notifies on keyboard appearing NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func keyboardWasShown(notification: NSNotification){ //Need to calculate keyboard exact size due to Apple suggestions self.scrollView.isScrollEnabled = true var info = notification.userInfo! let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeField = self.activeField { if (!aRect.contains(activeField.frame.origin)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } } } func keyboardWillBeHidden(notification: NSNotification){ //Once keyboard disappears, restore original positions var info = notification.userInfo! let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets self.view.endEditing(true) self.scrollView.isScrollEnabled = false } func textFieldDidBeginEditing(_ textField: UITextField){ activeField = textField } func textFieldDidEndEditing(_ textField: UITextField){ activeField = nil } 

这是我的2美分:

你有没有尝试过: https : //github.com/hackiftekhar/IQKeyboardManager

极易安装Swift或Objective-C。

这里是如何工作的:

IQKeyboardManager(Swift): – IQKeyboardManagerSwift可以通过CocoaPods进行安装,只需将以下行添加到您的Podfile:(#236)

 pod 'IQKeyboardManagerSwift' 

在AppDelegate.swift中,只需导入IQKeyboardManagerSwift框架并启用IQKeyboardManager。

 import IQKeyboardManagerSwift @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { IQKeyboardManager.sharedManager().enable = true return true } } 

这就是全部。 简单!

我发现为我完美工作的是这样的:

 func textFieldDidBeginEditing(textField: UITextField) { if textField == email || textField == password { animateViewMoving(true, moveValue: 100) } } func textFieldDidEndEditing(textField: UITextField) { if textField == email || textField == password { animateViewMoving(false, moveValue: 100) } } func animateViewMoving (up:Bool, moveValue :CGFloat){ let movementDuration:NSTimeInterval = 0.3 let movement:CGFloat = ( up ? -moveValue : moveValue) UIView.beginAnimations("animateView", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = CGRectOffset(self.view.frame, 0, movement) UIView.commitAnimations() } 

您也可以更改高度值。 如果要将其用于所有文本字段,请删除“if语句”。

你甚至可以使用这个需要像TextView的用户input的所有控件。

有没有办法让屏幕底部字段被编辑时才移动?

我有一个类似的问题,发现了一个非常简单的解决scheme, 而不使用scrollView,而是使用keyboardWillShow / Hide方法中的if语句。

 func keyboardWillShow(notification: NSNotification) { if bottomText.editing{ self.view.window?.frame.origin.y = -1 * getKeyboardHeight(notification) } } func keyboardWillHide(notification: NSNotification) { if self.view.window?.frame.origin.y != 0 { self.view.window?.frame.origin.y += getKeyboardHeight(notification) } } 

这对我来说是一个很好的解决scheme,因为我只有两个文本字段。

将整个视图向上移动:仅在编辑某些文本字段(bottomText)时

只有当视图不在原始位置时,才会将整个视图向下移动

为什么不在UITableViewController中实现呢? 显示时,键盘不会隐藏任何文本字段。

斯威夫特3扩展

  1. 将button添加到一个容器中
  2. 使用IBOutlet containerBtmConstrain连接容器的底部约束
  3. inViewDidLoad

     self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain self.watchForKeyboard() 
  4. 添加以下扩展名

     private var xoAssociationKeyForBottomConstrainInVC: UInt8 = 0 extension UIViewController { var containerDependOnKeyboardBottomConstrain :NSLayoutConstraint! { get { return objc_getAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC) as? NSLayoutConstraint } set(newValue) { objc_setAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) } } func watchForKeyboard () { NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown(notification:)), name:NSNotification.Name.UIKeyboardWillShow, object: nil); NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name:NSNotification.Name.UIKeyboardWillHide, object: nil); } func keyboardWasShown(notification: NSNotification) { let info = notification.userInfo! let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue UIView.animate(withDuration: 0.3, animations: { () -> Void in self.containerDependOnKeyboardBottomConstrain.constant = keyboardFrame.height self.view.layoutIfNeeded() }) } func keyboardWillHide(notification: NSNotification) { UIView.animate(withDuration: 0.3, animations: { () -> Void in self.containerDependOnKeyboardBottomConstrain.constant = 0 self.view.layoutIfNeeded() }) } } 

我觉得这个条款是错误的:

 if (!CGRectContainsPoint(aRect, activeField!.frame.origin)) 

虽然activeField的原点可能在键盘之上,但maxY可能不会…

我会为activeField创build一个“max”点,并检查它是否在键盘Rect中。

这是我的版本阅读苹果提供的文档和以前的post。 我注意到的一件事是textView没有被键盘覆盖处理。 不幸的是,苹果的文档不会工作,因为无论出于何种原因,在调用textViewDidBeginEditing之后调用键盘。 我通过调用一个核心方法来处理这个问题,该方法检查键盘是否显示,以及是否正在编辑textView或textField。 这样,这个过程只有在两个条件存在的时候才会被触发。

另一点与textViews是他们的高度可能是这样的键盘剪辑textView的底部,并不会调整,如果在左上angular的点在视图中。 所以,我写的代码实际上是采用屏幕引用的任何textView或textField的Bottom-Left点,并看看它是否落入所提供的键盘的屏幕参考坐标,这意味着键盘覆盖了它的一部分。

 let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil) if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY))) { // scroll textView/textField into view } 

如果您使用的是导航控制器,则子类也会将镶嵌的滚动视图自动调整设置为false。

 self.automaticallyAdjustsScrollViewInsets = false 

它遍历每个textView和textField来设置代理进行处理

  for view in self.view.subviews { if view is UITextView { let tv = view as! UITextView tv.delegate = self } else if view is UITextField { let tf = view as! UITextField tf.delegate = self } } 

只需将您的基类设置为在此创build的子类以获得结果。

 import UIKit class ScrollingFormViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate { var activeFieldRect: CGRect? var keyboardRect: CGRect? var scrollView: UIScrollView! override func viewDidLoad() { self.automaticallyAdjustsScrollViewInsets = false super.viewDidLoad() // Do any additional setup after loading the view. self.registerForKeyboardNotifications() for view in self.view.subviews { if view is UITextView { let tv = view as! UITextView tv.delegate = self } else if view is UITextField { let tf = view as! UITextField tf.delegate = self } } scrollView = UIScrollView(frame: self.view.frame) scrollView.scrollEnabled = false scrollView.showsVerticalScrollIndicator = false scrollView.showsHorizontalScrollIndicator = false scrollView.addSubview(self.view) self.view = scrollView } override func viewDidLayoutSubviews() { scrollView.sizeToFit() scrollView.contentSize = scrollView.frame.size super.viewDidLayoutSubviews() } deinit { self.deregisterFromKeyboardNotifications() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func registerForKeyboardNotifications() { //Adding notifies on keyboard appearing NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWasShown), name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWillBeHidden), name: UIKeyboardWillHideNotification, object: nil) } func deregisterFromKeyboardNotifications() { //Removing notifies on keyboard appearing NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) } func keyboardWasShown(notification: NSNotification) { let info : NSDictionary = notification.userInfo! keyboardRect = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() adjustForKeyboard() } func keyboardWillBeHidden(notification: NSNotification) { keyboardRect = nil adjustForKeyboard() } func adjustForKeyboard() { if keyboardRect != nil && activeFieldRect != nil { let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil) if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY))) { scrollView.scrollEnabled = true let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardRect!.size.height, 0.0) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets scrollView.scrollRectToVisible(activeFieldRect!, animated: true) } } else { let contentInsets : UIEdgeInsets = UIEdgeInsetsZero scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets scrollView.scrollEnabled = false } } func textViewDidBeginEditing(textView: UITextView) { activeFieldRect = textView.frame adjustForKeyboard() } func textViewDidEndEditing(textView: UITextView) { activeFieldRect = nil adjustForKeyboard() } func textFieldDidBeginEditing(textField: UITextField) { activeFieldRect = textField.frame adjustForKeyboard() } func textFieldDidEndEditing(textField: UITextField) { activeFieldRect = nil adjustForKeyboard() } } 

此代码向上移动您正在编辑的文本字段,以便您可以在Swift 3中查看此答案,您还必须使您的视图成为UITextFieldDelegate:

 var moveValue: CGFloat! var moved: Bool = false var activeTextField = UITextField() func textFieldDidBeginEditing(_ textField: UITextField) { self.activeTextField = textField } func textFieldDidEndEditing(_ textField: UITextField) { if moved == true{ self.animateViewMoving(up: false, moveValue: moveValue ) moved = false } } func animateViewMoving (up:Bool, moveValue :CGFloat){ let movementDuration:TimeInterval = 0.3 let movement:CGFloat = ( up ? -moveValue : moveValue) UIView.beginAnimations("animateView", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement) UIView.commitAnimations() } 

然后在viewDidLoad中:

 NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil) 

哪些调用(在viewDidLoad之外):

 func keyboardWillShow(notification: Notification) { if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue { let keyboardHeight = keyboardSize.height if (view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height < keyboardHeight{ moveValue = keyboardHeight - ((view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height) self.animateViewMoving(up: true, moveValue: moveValue ) moved = true } } } 

已经给出了令人敬畏的答案,但这是处理这种情况的另一种方法(使用Swift 3x ):

首先在viewWillAppear()调用以下方法

 func registerForKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown), name: NSNotification.Name.UIKeyboardDidShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillBeHidden), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } 

现在,像这样取一个UIView UIViewcontroller的顶部约束的IBOutlet :( 这里的UIViewUIScrollView的子视图,这意味着你应该有一个UIScrollView所有你的subViews

 @IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint! 

和另一个像下面的variables,并添加一个委托,即UITextFieldDelegate

 var activeTextField = UITextField() //This is to keep the reference of UITextField currently active 

之后,这里是神奇的部分只是粘贴下面的代码片段

 func keyboardWasShown(_ notification: Notification) { let keyboardInfo = notification.userInfo as NSDictionary? //print(keyboardInfo!) let keyboardFrameEnd: NSValue? = (keyboardInfo?.value(forKey: UIKeyboardFrameEndUserInfoKey) as? NSValue) let keyboardFrameEndRect: CGRect? = keyboardFrameEnd?.cgRectValue if activeTextField.frame.origin.y + activeTextField.frame.size.height + 10 > (keyboardFrameEndRect?.origin.y)! { UIView.animate(withDuration: 0.3, delay: 0, options: .transitionFlipFromTop, animations: {() -> Void in //code with animation //Print some stuff to know what is actually happening //print(self.activeTextField.frame.origin.y) //print(self.activeTextField.frame.size.height) //print(self.activeTextField.frame.size.height) self.loginViewTopConstraint.constant = -(self.activeTextField.frame.origin.y + self.activeTextField.frame.size.height - (keyboardFrameEndRect?.origin.y)!) - 30.0 self.view.layoutIfNeeded() }, completion: {(_ finished: Bool) -> Void in //code for completion }) } } func keyboardWillBeHidden(_ notification: Notification) { UIView.animate(withDuration: 0.3, animations: {() -> Void in self.loginViewTopConstraint.constant = self.view.frame.origin.y self.view.layoutIfNeeded() }) } //MARK: textfield delegates func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { activeTextField = textField return true } func textFieldShouldReturn(_ textField: UITextField) -> Bool { switch textField { case YOUR_TEXTFIELD_ONE: YOUR_TEXTFIELD_TWO.becomeFirstResponder() break case YOUR_TEXTFIELD_TWO: YOUR_TEXTFIELD_THREE.becomeFirstResponder() break default: textField.resignFirstResponder() break } return true } 

现在是最后一个片段:

 //Remove Keyboard Observers override func viewWillDisappear(_ animated: Bool) { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) } 

不要忘记将代表分配给UIStoryboard所有UITextField

祝你好运!

Swift 3语法:

 func textFieldDidBeginEditing(_ textField: UITextField) { // add if for some desired textfields animateViewMoving(up: true, moveValue: 100) } func textFieldDidEndEditing(_ textField: UITextField) { // add if for some desired textfields animateViewMoving(up: false, moveValue: 100) } func animateViewMoving (up:Bool, moveValue :CGFloat){ textFieldDidEndEditing(_ textField: UITextField) { let movementDuration:TimeInterval = 0.5 let movement:CGFloat = ( up ? -moveValue : moveValue) UIView.beginAnimations("animateView", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement) UIView.commitAnimations() } 

这是一个很好的方法来获得你想要的,你可以添加“如果”条件的某些文本字段,但这种types适用于所有…希望它可以是有用的

“我忘了提到我是Swift新手:(检查这个是什么将是正确的语法?(我怎样才能得到这个函数的字段名称?)”

好 。 首先确认到UITextFieldDelegate协议

 class YourClass:UITextFieldDelegate 

然后执行该function

 func textFieldDidBeginEditing(textField: UITextField!) { if textField == txtOne { println("TextOne") } if textField == txtTwo { println("TextTwo") } } 

您应该注意,正确的方法是使用滚动视图,并将应该在滚动视图内上下移动的视图相应地处理并相应地处理键盘事件

在下面的示例中,我只是在开始编辑txtLastName或txtCity时才将视图向上移动。 我创build了variableskeyboardActive,因为视图可以向上移动2x,如果我点击txtLastName和txtCity之后。

看一看,看看它是否适合你。

 class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var txtFirstName: UITextField! @IBOutlet weak var txtLastName: UITextField! @IBOutlet weak var txtCity: UITextField! var keyboardActive = false override func viewDidLoad() { super.viewDidLoad() self.txtFirstName.delegate = self self.txtLastName.delegate = self self.txtCity.delegate = self } func textFieldDidBeginEditing(textField: UITextField) { if textField != self.txtFirstName && keyboardActive == false { self.view.frame.origin.y -= 165 self.keyboardActive = true } } func textFieldShouldEndEditing(textField: UITextField) -> Bool { if textField != self.txtFirstName && keyboardActive == true { self.view.frame.origin.y += 165 self.keyboardActive = false } return true } func textFieldShouldReturn(textField: UITextField) -> Bool { self.view.endEditing(true) return false } } 

我使用了SwiftLint,它在接受的答案的格式上有几个问题。 特别:

没有空间之前的结肠,没有强制铸造,更喜欢UIEdgeInset(顶部:等…而不是UIEdgeInsetMake。

所以这里是Swift 3的更新

 func registerForKeyboardNotifications() { //Adding notifies on keyboard appearing NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func deregisterFromKeyboardNotifications() { //Removing notifies on keyboard appearing NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func keyboardWasShown(notification: NSNotification) { //Need to calculate keyboard exact size due to Apple suggestions scrollView?.isScrollEnabled = true var info = notification.userInfo! if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size { let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0) scrollView?.contentInset = contentInsets scrollView?.scrollIndicatorInsets = contentInsets var aRect: CGRect = self.view.frame aRect.size.height -= keyboardSize.height if let activeField = self.activeField { if !aRect.contains(activeField.frame.origin) { self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } } } } func keyboardWillBeHidden(notification: NSNotification) { //Once keyboard disappears, restore original positions var info = notification.userInfo! if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size { let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize.height, right: 0.0) scrollView?.contentInset = contentInsets scrollView?.scrollIndicatorInsets = contentInsets } view.endEditing(true) scrollView?.isScrollEnabled = false } func textFieldDidBeginEditing(_ textField: UITextField) { activeField = textField } func textFieldDidEndEditing(_ textField: UITextField) { activeField = nil } 

Swift 3

 @IBOutlet var scrollView: UIScrollView! @IBOutlet var edtEmail: UITextField! @IBOutlet var bottomTextfieldConstrain: NSLayoutConstraint! // <- this guy is the constrain that connect the bottom of textField to lower object or bottom of page! @IBAction func edtEmailEditingDidBegin(_ sender: Any) { self.bottomTextfieldConstrain.constant = 200 let point = CGPoint(x: 0, y: 200) scrollView.contentOffset = point } @IBAction func edtEmailEditingDidEnd(_ sender: Any) { self.bottomTextfieldConstrain.constant = 50 } 

被接受的anwser近乎完美。 但是我需要使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey,因为后者返回keyborad的高度为0.并且将testing点改为底部而不是原点。

  var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeField = self.activeField { var point = activeField.frame.origin point.y += activeField.frame.size.height if (!aRect.contains(point)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } } 

首先声明一个variables来标识你的活动UITextField。

步骤1:-

var activeTextField: UITextField

第2步: – 在这之后,在viewDidLoad中添加这两行。

 NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 

第3步: –

现在在您的控制器类中定义这两个方法。

 func keyboardWillShow(_ notification: NSNotification) { self.scrollView.isScrollEnabled = true var info = notification.userInfo! let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeField = self.activeField { if (!aRect.contains(activeField.frame.origin)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } } } func keyboardWillHide(_ notification: NSNotification) { let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets self.view.endEditing(true) self.scrollView.isScrollEnabled = true } func textFieldDidBeginEditing(_ textField: UITextField){ activeField = textField } func textFieldDidEndEditing(_ textField: UITextField){ activeField = nil }