只有当键盘覆盖输入字段时才向上移动视图

我正在尝试为 iPhone 搭建一个输入屏幕。屏幕上有许多输入字段。它们大多数位于屏幕的顶部,但有两个字段位于底部。 当用户试图编辑屏幕底部的文本时,键盘将弹出并覆盖屏幕。 我找到了一个简单的解决方案,当这种情况发生时,将屏幕向上移动,但结果是,当用户试图编辑屏幕时,屏幕 一直都是向上移动,屏幕顶部的字段向上移动。

当底部字段被编辑时,有没有一种方法可以让屏幕 只有移动?

我用这个代码找到了 给你:

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
}
201353 次浏览

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

你的问题在 这份苹果公司的文件中得到了很好的解释。这个页面上的示例代码(在 Listing 4-1)完全满足您的需要,它只会在当前编辑应该在键盘下时滚动您的视图。您只需将所需的控件放在 scrollView 中。 唯一的问题是,这是 Objective-C,我认为你需要在 Swift 中使用它... ... 所以... ... 这里是:

声明一个变量

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 上调用 registerForKeyboardNotifications,在 exit 上调用 deregisterFromKeyboardNotifications

编辑/更新: Swift 4.2语法

func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}


func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}


@objc 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[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 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)
}
}
}


@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 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
}

“我忘了说我是 Swift 的新手: (检查这个的正确语法是什么?(如何在这个函数中获得字段名?)”

好的,首先确认 UITextField 委托协议

class YourClass:UITextFieldDelegate

然后实现这个函数

func textFieldDidBeginEditing(textField: UITextField!) {


if textField == txtOne
{
println("TextOne")
}
if textField == txtTwo
{
println("TextTwo")
}
}

您应该注意到,正确的方法是使用 scrollview 并将应该向上/向下移动的视图放置在捲动视图中,并相应地处理键盘事件

我认为这个条款是错误的:

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

ActiveField 的起源可能在键盘上方,而 maxY 可能不在键盘上方。

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

这是我的建议:

你试过了吗: https://github.com/hackiftekhar/IQKeyboardManager

极易安装 Swift 或 Objective-C。

它是这样运作的:

IQKeyboardManager (Swift) :-IQKeyboardManagerSwift 可以通过 CocoaPods 安装,只需在您的 Podfile 中添加以下代码即可: (# 236)

pod 'IQKeyboardManagerSwift'

只需导入 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
// For Swift 4, use this instead
// IQKeyboardManager.shared.enable = true




return true
}
}

就这样,放松!

底部油田被编辑的时候,有没有办法让屏幕 只有移动?

我也遇到过类似的问题,我发现了一个非常简单的解决方案 没有,它使用 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)
}
}

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

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

仅当视图不在原始位置时,才将整个视图向下移动:

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

TextView 的另一个特点是,它们的高度可能是这样的: 键盘剪切 textView 的底部,如果视图的左上角在视图中,它们就不会调整。因此,我编写的代码实际上采用了任何 textView 或 textField 的屏幕引用的左下角点,并查看它是否位于显示的键盘的屏幕引用坐标中,这意味着键盘覆盖了它的一部分。

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

如果您使用的是导航控制器,那么子类还会将 insets 的滚动视图自动调整设置为 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
}
}

只需将基类设置为此处为结果创建的子类。

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()
}


}

我发现最适合我的是这个:

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。

这段代码移动到你正在编辑的文本字段,这样你就可以在 Swift 3中查看这个答案,你还必须将你的视图设置为 UITextFieldCommittee:

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
}
}
}

我使用 SwiftLint,它在已接受答案的格式方面有一些问题。具体来说:

结肠前没有空格, 没有强制施法, 更喜欢 UIEdgeInsetMake (顶部等)而不是 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
}

我们已经给出了很棒的答案,但这是处理这种情况的另一种方法(使用 斯威夫特3倍) :

首先在 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)


}

现在取一个 UIViewUIViewcontroller的最高约束,如下所示: (这里的 ABC1是 UIScrollView的子视图,这意味着你所有的 ABC6都应该有一个 UIScrollView)

@IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!

以及另一个变量,比如 following 和 add,一个委托,即 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 4(* * update )带扩展名 * *

  1. 在一个容器中添加按钮
  2. 将容器的底部约束与 IBOutlet Container 连接起来
  3. InViewDidLoad

    self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
    self.watchForKeyboard()
    
  4. add the following extension

    import UIKit
    
    
    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:UIResponder.keyboardWillShowNotification, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name:UIResponder.keyboardWillHideNotification, object: nil);
    }
    
    
    @objc func keyboardWasShown(notification: NSNotification) {
    let info = notification.userInfo!
    guard let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
    return
    }
    
    
    UIView.animate(withDuration: 0.3, animations: { () -> Void in
    self.containerDependOnKeyboardBottomConstrain.constant = -keyboardFrame.height
    self.view.layoutIfNeeded()
    })
    }
    
    
    @objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.3, animations: { () -> Void in
    self.containerDependOnKeyboardBottomConstrain.constant = 0
    self.view.layoutIfNeeded()
    })
    }
    }
    

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()
}

这是一个得到你想要的东西的好方法 您可以为某些文本字段添加“ if”条件 但是这种类型适用于所有人... 希望它对所有人都有用

公认的答案几乎是完美的。但是我需要使用 UIKeyboardFrameEndUserInfoKey而不是 UIKeyboardFrameBeginUserInfoKey,,因为后者返回键盘高度0。并将最高点更改为底部非原点。

    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)
}
}

首先声明一个变量来标识活动的 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)

第三步:-

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

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
}

Swift 4更新了我的解决方案

使用键盘上的约束动画显示/隐藏, 好好享受。

import Foundation
import UIKit


class PhoneController: UIViewController, UITextFieldDelegate{


var phoneLayoutYConstraint: NSLayoutConstraint?


override func viewDidLoad() {


super.viewDidLoad()


view.backgroundColor = .white


NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
phoneField.delegate = self


view.addSubview(phoneField)


NSLayoutConstraint.activate([phoneField.heightAnchor.constraint(equalToConstant: 50),
phoneField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
phoneField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
phoneField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)])


phoneLayoutYConstraint = NSLayoutConstraint(item: phoneField, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
phoneLayoutYConstraint?.isActive = true


}


let phoneField: UITextField = {
let text = UITextField()
text.translatesAutoresizingMaskIntoConstraints = false
text.keyboardType = .numberPad
text.font = UIFont.systemFont(ofSize: 30)
text.layer.cornerRadius = 5.0
text.layer.masksToBounds = true
text.layer.borderColor = UIColor.darkGray.cgColor
text.layer.borderWidth = 2.0


return text
}()




override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}


func textFieldDidBeginEditing(_ textField: UITextField) {


}




func textFieldDidEndEditing(_ textField: UITextField) {


}


func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}




@objc func handleKeyBoardNotification(_ notification: NSNotification) {


if let info = notification.userInfo {


let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let isKeyBoardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow


var aRect : CGRect = self.phoneField.frame
aRect.size.height -= keyboardSize!.height




phoneLayoutYConstraint?.constant = isKeyBoardShowing ? -keyboardSize!.height : 0


UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: { (boo) in


})


}
}


}

Swift 4

你可以轻松地移动上下 UITextField与动画键盘

enter image description here

import UIKit


class ViewController: UIViewController {


@IBOutlet var textField: UITextField!


override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textField.resignFirstResponder()
}


@objc func keyboardWillChange(notification: NSNotification) {


let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y


UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.textField.frame.origin.y+=deltaY


},completion: nil)
}

只要使用这个扩展来移动任何 UIView 当键盘出现。

extension UIView {
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChange(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}


@objc func keyboardWillChange(_ notification: NSNotification){
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let beginningFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue


let deltaY = endFrame.origin.y - beginningFrame.origin.y


UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.origin.y += deltaY
}, completion: nil)
}
}

然后在你的视图中将你的视图绑定到键盘上

UiView.bindToKeyboard()

Swift 4.2

如果 UITextField的位置在键盘下面,我的解决方案将(垂直)使视图居中。

步骤1: 创建新的快捷文件并复制粘贴 UIViewWithKeyboard类。
第二步: 在 Interface Builder 中设置为自定义类为您的最高 UIView

import UIKit


class UIViewWithKeyboard: UIView {
@IBInspectable var offsetMultiplier: CGFloat = 0.75
private var keyboardHeight = 0 as CGFloat
private weak var activeTextField: UITextField?
override func awakeFromNib() {
super.awakeFromNib()
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.textDidBeginEditing),
name: UITextField.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillShow),
name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillHide),
name: UIResponder.keyboardWillHideNotification, object: nil)
}


@objc func textDidBeginEditing(_ notification: NSNotification) {
self.activeTextField = notification.object as? UITextField
}


@objc func keyboardWillShow(_ notification: Notification) {
if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
keyboardHeight = frameValue.cgRectValue.size.height
if let textField = self.activeTextField {
let offset = textField.frame.maxY < frame.maxY - keyboardHeight ? 0
: textField.frame.maxY - (frame.maxY - keyboardHeight) * offsetMultiplier
self.setView(offset: offset)
}
}
}


@objc func keyboardWillHide(_ notification: NSNotification) {
self.setView(offset: 0)
}


func setView(offset: CGFloat) {
UIView.animate(withDuration: 0.25) {
self.bounds.origin.y = offset
}
}
}

快速4.2。

这将适用于任何形式。没有滚动视图的需要。 不要忘记设置委托。

创建 uitextfield 的 var

var clickedTextField = UITextField()

在你的视野里

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);

了解单击的文本字段。可能你在整个屏幕上都有文本字段。

func textFieldDidBeginEditing(_ textField: UITextField) {
clickedTextField = textField
}

检查键盘是否覆盖文本字段。

@objc func keyboardWillShow(sender: NSNotification,_ textField : UITextField) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {


if clickedTextField.frame.origin.y > keyboardSize.origin.y {
self.view.frame.origin.y = keyboardSize.origin.y - clickedTextField.center.y - 20
}
}
}


@objc func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y = 0
}

回到关闭键盘

func textFieldShouldReturn(_ textField: UITextField) -> Bool {   //delegate method
textField.resignFirstResponder()
return true
}

更新: NSNotification. Name.UIKeyboardWillShow & NSNotification. Name.UIKeyboardWillHide 分别重命名为 UIResponder.keyboardWillShowNotification & UIResponder.keyboardWillHideNotification。

改写为迅捷4.2

在 ViewDidLoad. 。

 NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWasShown), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWillBeHidden), name: UIResponder.keyboardWillHideNotification, object: nil)

剩余职能

func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}


func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}


@objc 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[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 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)
}
}
}


@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 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
}

为了 Swift 4.2

此代码将允许您控制特定设备屏幕大小的帧的 Y 轴力矩。

PS: 此代码不会根据 TextField 的位置智能地移动帧

为 UIDevice 创建扩展

extension UIDevice {
enum ScreenType: String {
case iPhone4_4S = "iPhone 4 or iPhone 4s"
case iPhones_5_5s_5c_SE = "iPhone 5, iPhone 5s, iPhone 5c or iPhone SE"
case iPhones_6_6s_7_8 = "iPhone 6, iPhone 6s, iPhone 7 or iPhone 8"
case iPhones_6Plus_6sPlus_7Plus_8Plus = "iPhone 6 Plus, iPhone 6s Plus, iPhone 7 Plus or iPhone 8 Plus"
case iPhoneX_Xs = "iPhone X, iPhone Xs"
case iPhoneXR = "iPhone XR"
case iPhoneXSMax = "iPhone Xs Max"
case unknown
}
var screenType: ScreenType {
switch UIScreen.main.nativeBounds.height {
case 960:
return .iPhone4_4S
case 1136:
return .iPhones_5_5s_5c_SE
case 1334:
return .iPhones_6_6s_7_8
case 1920, 2208:
return .iPhones_6Plus_6sPlus_7Plus_8Plus
case 1792:
return .iPhoneXR
case 2436:
return .iPhoneX_Xs
case 2688:
return .iPhoneXSMax
default:
return .unknown
}
}
}

在 viewDidLoad 上添加 NotificationObserver

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

选择器

@objc func keyboardWillShow(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
if self.view.frame.origin.y == 0 {
switch (UIDevice.current.screenType.rawValue) {
case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
self.view.frame.origin.y -= 210
case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
self.view.frame.origin.y -= 110
case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
self.view.frame.origin.y -= 80
case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
self.view.frame.origin.y -= 70
case (UIDevice.ScreenType.iPhoneXR.rawValue):
self.view.frame.origin.y -= 70
case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
self.view.frame.origin.y -= 70
default:
self.view.frame.origin.y -= 150
}
}
}
}


@objc func keyboardWillHide(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
if self.view.frame.origin.y != 0 {
switch (UIDevice.current.screenType.rawValue) {
case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
self.view.frame.origin.y += 210
case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
self.view.frame.origin.y += 110
case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
self.view.frame.origin.y += 80
case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
self.view.frame.origin.y += 70
case (UIDevice.ScreenType.iPhoneXR.rawValue):
self.view.frame.origin.y += 70
case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
self.view.frame.origin.y += 70
default:
self.view.frame.origin.y += 150
}
}
}
}

Swift : 可以通过检查显示哪个 textField 来实现这一点。

@objc func keyboardWillShow(notification: NSNotification) {
if self.textField.isFirstResponder == true {
self.view.frame.origin.y -= 150
}
}


@objc func keyboardWillHide(notification: NSNotification){
if self.textField.isFirstResponder == true {
self.view.frame.origin.y += 150
}
}

由于没有答案关于如何做到这一点,在组合,这里是我使用的方法。

  1. 我们创建一个发布者来监听通知、显示和隐藏。
  2. 为了显示,我们从通知 userInfo中获得了键盘的框架,并检查 当前有源应答器是否包含在其中。如果它的覆盖返回键盘帧高度。如果它不是覆盖返回0,我们不想移动框架。对于 hide 通知,我们只返回0。
private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect }
.map { $0.intersects(self.view.firstResponder!.frame) ? $0.height : 0 }
.map { $0 * -1 },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
).eraseToAnyPublisher()
}

viewDidLoad中,我们只需订阅发布者相应地更改视图框架。

override func viewDidLoad() {
super.viewDidLoad()


keyboardHeightPublisher.sink{ [weak self] height in
self?.view.frame.origin.y = height
}.store(in: &cancelables)
}

剪辑
小心点!如果 firstResponder位于子视图中,则必须计算与整个屏幕对应的帧,以检查它们是否实际相交。
例如:

let myViewGlobalFrame = myView.convert(myView.frame, to: parentView)