使用Swift键盘移动视图

我有一个应用程序,在视图的下半部分有一个文本字段。 这意味着当我在文本框中输入时,键盘会覆盖文本框

我如何在打字时向上移动视图,这样我就可以看到我键入的内容,然后在键盘消失时将它移回原来的位置?

我到处都看了,但所有的解似乎都在Obj-C中,我还不能完全转换。

任何帮助都将不胜感激。

270405 次浏览

将这个添加到你的视图控制器中。效果非常好。只是调整数值。

override func viewDidLoad() {
super.viewDidLoad()
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);
}


@objc func keyboardWillShow(sender: NSNotification) {
self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y += 150
}

这是一个解决方案,不处理从一个textField到另一个切换:

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(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y -= keyboardSize.height
}
}


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

要解决这个问题,将两个函数keyboardWillShow/Hide替换为:

func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}


func keyboardWillHide(notification: NSNotification) {
if view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}

斯威夫特3.0:

override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}


@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}


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

斯威夫特4.0:

override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}


@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}


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

斯威夫特4.2:

override func viewDidLoad() {
super.viewDidLoad()
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 let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}


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

我注意到其他答案涉及从视图中删除一些顶部。如果你想简单地调整视图的大小而不削减任何内容,只需尝试这个方法:)

func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
}
}


func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
}
}

在这个线程中,一个流行的答案使用了以下代码:

func keyboardWillShow(sender: NSNotification) {
self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
self.view.frame.origin.y += 150
}

用一个静态量来抵消你的视图有一个明显的问题。它在一个设备上看起来很好,但在任何其他尺寸配置上看起来都很糟糕。您需要获取键盘高度并将其用作偏移值。

下面是一个解决方案,适用于所有设备,并处理用户在输入时隐藏预测文本字段的边缘情况。

解决方案

下面需要注意的是,我们将self.view.window作为对象参数传入。这将为我们提供来自键盘的数据,比如它的高度!

@IBOutlet weak var messageField: UITextField!


override func viewDidLoad() {
super.viewDidLoad()


NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: self.view.window)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: self.view.window)
}


func keyboardWillHide(sender: NSNotification) {
let userInfo: [NSObject : AnyObject] = sender.userInfo!
let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
self.view.frame.origin.y += keyboardSize.height
}

我们将使它在所有设备上看起来都很漂亮,并处理用户添加或删除预测文本字段的情况。

func keyboardWillShow(sender: NSNotification) {
let userInfo: [NSObject : AnyObject] = sender.userInfo!
let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size


if keyboardSize.height == offset.height {
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y -= keyboardSize.height
})
} else {
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y += keyboardSize.height - offset.height
})
}
}

删除观察者

不要忘记在离开视图之前删除您的观察器,以防止传输不必要的消息。

override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

根据评论中的问题更新:

如果你有两个或更多的文本字段,你可以检查你的view.frame.origin.y是否为零。

func keyboardWillShow(sender: NSNotification) {
let userInfo: [NSObject : AnyObject] = sender.userInfo!


let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size


if keyboardSize.height == offset.height {
if self.view.frame.origin.y == 0 {
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y -= keyboardSize.height
})
}
} else {
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.view.frame.origin.y += keyboardSize.height - offset.height
})
}
print(self.view.frame.origin.y)
}

Swift 3更新…

正如其他人所说,你需要在控制器的viewDidLoad()方法中添加通知观察者,如下所示:

NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
{ notification in
self.keyboardWillShow(notification)
}


NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
{ notification in
self.keyboardWillHide(notification)
}


NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
{ _ in
self.enableUserInteraction()
}


NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
{ _ in
self.enableUserInteraction()
}

记得在适当的地方删除你的观察器(我在viewWillDisappear()方法中这样做)

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)

然后,实现你的show和hide方法——注意告诉应用程序忽略交互事件的行(beginIgnoringInteractionEvents)。这很重要,因为如果没有它,用户可能会点击一个字段甚至滚动视图,导致第二次发生移位,从而导致可怕的UI故障。在键盘显示和隐藏之前忽略交互事件将防止这种情况:

func keyboardWillShow(notification: Notification)
{
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
{
UIApplication.shared.beginIgnoringInteractionEvents()
self.view.frame.origin.y -= keyboardSize.height
// add this line if you are shifting a scrollView, as in a chat application
self.timelineCollectionView.contentInset.top += keyboardSize.height
}
}


func keyboardWillHide(notification: Notification)
{
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
{
UIApplication.shared.beginIgnoringInteractionEvents()
self.view.frame.origin.y += keyboardSize.height
// add this line if you are shifting a scrollView, as in a chat application
self.timelineCollectionView.contentInset.top -= keyboardSize.height
}
}

最后,重新启用用户交互(记住,这个方法在键盘didShow或didHide之后触发):

func enableUserInteraction()
{
UIApplication.shared.endIgnoringInteractionEvents()
}

我看到所有的答案都是通过键盘高度的值移动视图本身。好吧,我有一个详细的答案,这可能是有用的,如果你正在使用约束,即autolayout,通过改变它的约束值(底部或顶部约束为例)通过一个预定义的值移动视图,或者你可以使用键盘大小值。

在这个例子中,我使用底部约束从文本字段到底部布局视图的初始值为175。

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!


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(notification: NSNotification) {
//To retrieve keyboard size, uncomment following line
//let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
bottomConstraint.constant = 260
UIView.animateWithDuration(0.3) {
self.view.layoutIfNeeded()
}
}


func keyboardWillHide(notification: NSNotification) {
//To retrieve keyboard size, uncomment following line
//let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
bottomConstraint.constant = 175
UIView.animateWithDuration(0.3) {
self.view.layoutIfNeeded()
}
}

最简单的方法,甚至不需要任何代码:

  1. 下载KeyboardLayoutConstraint.swift并添加(拖放;drop)文件到你的项目中,如果你还没有使用Spring动画框架。
  2. 在你的故事板中,为视图或文本字段创建一个底部约束,选择约束(双击它),在标识检查器中,将其类从NSLayoutConstraint更改为KeyboardLayoutConstraint。
  3. 完成了!

物体会随着键盘同步自动移动。

这个视频教程是最好的。7分钟长,会很有意义。这样一个简单的解决方案,当你有多个文本字段,并希望滚动视图移动“x”数量的像素时,特定的文本字段被点击。

< a href = " https://youtu。/ VuiPGJOEBH4”rel = " https://youtu.be/VuiPGJOEBH4 nofollow”> < / >

就这些步骤:

-把你所有的文本字段放在一个滚动视图中,约束到视图的边缘。

-连接所有的文本字段和滚动视图作为视图控制器的委托。

-用IBOutlet连接所有文本字段和滚动视图。

class ViewController: UIViewController, UITextFieldDelegate {

添加UITextFieldDelegate协议到你的类中

@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!
@IBOutlet weak var scrollView: UIScrollView!

-在swift文件中添加UITextFieldDelegate方法:

func textFieldShouldReturn(textField: UITextField) -> Bool {


textField.resignFirstResponder()
return true
}




func textFieldDidBeginEditing(textField: UITextField) {


if (textField == self.stateAddress) {
scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
}
else if (textField == self.zipAddress) {
scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
}
else if (textField == self.phoneNumber) {
scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
}
else if (textField == self.vetEmailAddress) {
scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
}
}


func textFieldDidEndEditing(textField: UITextField) {


scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}

第一种方法只是激活键盘上的返回按钮来关闭键盘。第二个是当你点击到任何特定的文本域,然后设置你的滚动视图滚动的距离的y偏移(我的是基于我的视图控制器上的y位置25,57,112,142)。最后一个说,当你从键盘上点击时,滚动视图会回到原来的位置。

我使我的视图像素完美的这种方式!

这是我的解决方案(实际上这段代码是在你的视图中有几个文本字段的情况下,这也适用于当你有一个文本字段的情况下)

class MyViewController: UIViewController, UITextFieldDelegate {


@IBOutlet weak var firstTextField: UITextField!
@IBOutlet weak var secondTextField: UITextField!


var activeTextField: UITextField!
var viewWasMoved: Bool = false




override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}


override func viewDidDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}


func textFieldDidBeginEditing(textField: UITextField) {
self.activeTextField = textField
}


func textFieldDidEndEditing(textField: UITextField) {
self.activeTextField = nil
}


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




func keyboardWillShow(notification: NSNotification) {


let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()


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


let activeTextFieldRect: CGRect? = activeTextField?.frame
let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin


if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
self.viewWasMoved = true
self.view.frame.origin.y -= keyboardSize!.height
} else {
self.viewWasMoved = false
}
}


func keyboardWillHide(notification: NSNotification) {
if (self.viewWasMoved) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y += keyboardSize.height
}
}
}
这个功能应该在Ios中内置,但是我们需要在外部做 插入以下代码
*当textField在键盘下时移动视图,
*当textField在键盘
时不移动视图 *在需要时根据键盘高度移动视图

import UIKit


class NamVcc: UIViewController, UITextFieldDelegate
{
@IBOutlet weak var NamTxtBoxVid: UITextField!


var VydTxtBoxVar: UITextField!
var ChkKeyPadDspVar: Bool = false
var KeyPadHytVal: CGFloat!


override func viewDidLoad()
{
super.viewDidLoad()


NamTxtBoxVid.delegate = self
}


override func viewWillAppear(animated: Bool)
{
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(TdoWenKeyPadVyd(_:)),
name:UIKeyboardWillShowNotification,
object: nil);
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(TdoWenKeyPadHyd(_:)),
name:UIKeyboardWillHideNotification,
object: nil);
}


func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
{
self.VydTxtBoxVar = TxtBoxPsgVar
}


func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
{
self.VydTxtBoxVar = nil
}


func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
{
self.VydTxtBoxVar.resignFirstResponder()
return true
}


override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}


func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
{
if(!self.ChkKeyPadDspVar)
{
self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height


var NonKeyPadAraVar: CGRect = self.view.frame
NonKeyPadAraVar.size.height -= self.KeyPadHytVal


let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin


if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
{
self.ChkKeyPadDspVar = true
UIView.animateWithDuration(1.0,
animations:
{ self.view.frame.origin.y -= (self.KeyPadHytVal)},
completion: nil)
}
else
{
self.ChkKeyPadDspVar = false
}
}


}


func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
{
if (self.ChkKeyPadDspVar)
{
self.ChkKeyPadDspVar = false
UIView.animateWithDuration(1.0,
animations:
{ self.view.frame.origin.y += (self.KeyPadHytVal)},
completion: nil)
}
}


override func viewDidDisappear(animated: Bool)
{
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
view.endEditing(true)
ChkKeyPadDspVar = false
}
}

|::|有时候视图会向下,在这种情况下使用高度+/- 150:

    NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150


{ self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
completion: nil)


{ self.view.frame.origin.y += self.KeyPadHytVal  - 150},
completion: nil)
func keyboardWillShow(notification: NSNotification) {


if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
}


}


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

它必须更加稳定

 override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)


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


}


// MARK: - keyboard
func keyboardWillShow(notification: NSNotification)
{


if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
// ...
} else {
// no UIKeyboardFrameBeginUserInfoKey entry in userInfo
}
} else {
// no userInfo dictionary in notification
}
}


func keyboardWillHide(notification: NSNotification)
{
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
}

使用以下代码查看UITextField单击

func textFieldDidBeginEditing(textField: UITextField) {
ViewUpanimateMoving(true, upValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
ViewUpanimateMoving(false, upValue: 100)
}
func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
var durationMovement:NSTimeInterval = 0.3
var movement:CGFloat = ( up ? -upValue : upValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(durationMovement)
self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
UIView.commitAnimations()
}

如果你在同一个VC中有2个或更多的文本字段,用户点击其中一个,然后点击另一个,不调用keyboardWillHide函数,视图会再向上一次,这是不必要的,因为你会有键盘,一个空格,它有键盘的高度,然后视图,使用我编辑的答案中的代码:

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(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y -= keyboardSize.height
}
}


func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y += keyboardSize.height
}
}

为了解决这个问题,将两个函数"KeyboardWillShow/Hide"替换为:

func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}


func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y != 0 {
self.view.frame.origin.y += keyboardSize.height
}
}
}

我做了一个椰子荚来简化问题:

https://github.com/xtrinch/KeyboardLayoutHelper

如何使用:

创建一个自动布局的底部约束,给它一个KeyboardLayoutConstraint类在模块KeyboardLayoutHelper和荚将做必要的工作来增加它,以适应出现和消失的键盘。看例子项目上的例子如何使用它(我做了两个:一个scrollView内的textFields,和垂直中心的textFields与两个基本视图-登录&注册)。

底部布局约束可以是容器视图,textField本身,任何你能想到的。

func registerForKeyboardNotifications()
{
//Keyboard
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardDidHideNotification, object: nil)




}
func deregisterFromKeyboardNotifications(){


NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)


}
func keyboardWasShown(notification: NSNotification){


let userInfo: NSDictionary = notification.userInfo!
let keyboardInfoFrame = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue()


let windowFrame:CGRect = (UIApplication.sharedApplication().keyWindow!.convertRect(self.view.frame, fromView:self.view))


let keyboardFrame = CGRectIntersection(windowFrame, keyboardInfoFrame!)


let coveredFrame = UIApplication.sharedApplication().keyWindow!.convertRect(keyboardFrame, toView:self.view)


let contentInsets = UIEdgeInsetsMake(0, 0, (coveredFrame.size.height), 0.0)
self.scrollViewInAddCase .contentInset = contentInsets;
self.scrollViewInAddCase.scrollIndicatorInsets = contentInsets;
self.scrollViewInAddCase.contentSize = CGSizeMake((self.scrollViewInAddCase.contentSize.width), (self.scrollViewInAddCase.contentSize.height))


}
/**
this method will fire when keyboard was hidden


- parameter notification: contains keyboard details
*/
func keyboardWillBeHidden (notification: NSNotification) {


self.scrollViewInAddCase.contentInset = UIEdgeInsetsZero
self.scrollViewInAddCase.scrollIndicatorInsets = UIEdgeInsetsZero


}

swift 3.0插入在viewDidLoad(),这->

view.addSubview (Your_messageInputConteinerView)

    view.addConstraintWithFormat(format: "H:|[v0]|", views:Your_messageInputConteinerView)


view.addConstraintWithFormat(format: "V:[v0(48)]", views:Your_messageInputConteinerView)

addobserver (self, selector: #selector(handleKeyboardNotification(notification:))), name: NSNotification.Name。对象:nil)

addobserver (self, selector: #selector(handleKeyboardNotification(notification:))),名称:.UIKeyboardWillHide,对象:nil)

bottomConstraint = NSLayoutConstraint(item: Your_messageInputConteinerView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)


view.addConstraint(bottomConstraint!)

func handleKeyboardNotification(通知:通知){

if let userInfo = notification.userInfo {


if let keyBoardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue{


print(keyBoardFrame)


if bottomConstraint?.constant != CGFloat(0) {
bottomConstraint?.constant = 0
return
}
bottomConstraint?.constant = -keyBoardFrame.height
or
self.view.frame.origin.y = -keyBoardFrame.height
}
}

Swift 3代码

var activeField: UITextField?


override func viewDidLoad() {
super.viewDidLoad()


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


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


func textFieldDidEndEditing(_ textField: UITextField){
activeField = nil
}


func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
} else {
self.view.frame.origin.y = 0
}
}
}


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

我已经阅读了答案,并通过以下代码行解决了我的问题:

class ViewController: UIViewController, UITextFieldDelegate {


@IBOutlet weak var titleField: UITextField!
@IBOutlet weak var priceField: UITextField!
@IBOutlet weak var detailsField: UTtextField!


override func viewDidLoad() {
super.viewDidLoad()
// Do not to forget to set the delegate otherwise the textFieldShouldReturn(_:)
// won't work and the keyboard will never be hidden.
priceField.delegate = self
titleField.delegate = self
detailsField.delegate = self


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 textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}


func keyboardWillShow(notification: NSNotification) {
var translation:CGFloat = 0
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if detailsField.isEditing{
translation = CGFloat(-keyboardSize.height)
}else if priceField.isEditing{
translation = CGFloat(-keyboardSize.height / 3.8)
}
}
UIView.animate(withDuration: 0.2) {
self.view.transform = CGAffineTransform(translationX: 0, y: translation)
}
}




func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.2) {
self.view.transform = CGAffineTransform(translationX: 0, y: 0)
}
}
}

我有几个UITextFields,并希望视图移动不同取决于哪个textField被点击。

对于斯威夫特3

func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder


//move textfields up
let myScreenRect: CGRect = UIScreen.main.bounds
let keyboardHeight : CGFloat = 216


UIView.beginAnimations( "animateView", context: nil)
var movementDuration:TimeInterval = 0.35
var needToMove: CGFloat = 0


var frame : CGRect = self.view.frame
if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
}


frame.origin.y = -needToMove
self.view.frame = frame
UIView.commitAnimations()
}


func textFieldDidEndEditing(_ textField: UITextField) {
//move textfields back down
UIView.beginAnimations( "animateView", context: nil)
var movementDuration:TimeInterval = 0.35
var frame : CGRect = self.view.frame
frame.origin.y = 0
self.view.frame = frame
UIView.commitAnimations()
}

如果你像我一样尝试了以上所有的解决方案,但你的问题仍然没有解决,我有一个很棒的解决方案,它就像一个魅力。首先我想澄清一下上面提到的一些解决方案。

    在我的案例中,IQkeyboardmanager只在没有应用于元素上的自动布局时工作,如果应用了,那么IQkeyboardmanager将不工作
  1. 向上移动self。view也是一样。
  2. 我写了一个objective c头与快速支持推UITexfield向上当用户点击它,解决键盘覆盖UITextfield: https://github.com/coolvasanth/smart_keyboard的问题。
  3. 在iOS应用程序开发方面具有中级或更高水平的人可以轻松理解存储库并实现它。愿一切都好!

对于Swift 3,我做了一个UIViewController子类,因为我需要在所有的视图控制器中恒定的行为。

class SomeClassVC: UIViewController {


//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()


addKeyboardObservers()
}


override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)


removeKeyboardObservers()
}


//MARK: - Overrides
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}


//MARK: - Help
func addKeyboardObservers() {
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 removeKeyboardObservers() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
}


func keyboardWillShow(notification: NSNotification) {
let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.window?.frame.origin.y = -1 * keyboardHeight!
self.view.layoutIfNeeded()
})
}


func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.window?.frame.origin.y = 0
self.view.layoutIfNeeded()
})
}


func resignTextFieldFirstResponders() {
for textField in self.view.subviews where textField is UITextField {
textField.resignFirstResponder()
}
}


func resignAllFirstResponders() {
view.endEditing(true)
}
}

我改进了其中一个答案,使其适用于不同的键盘和放大器;不同的文本视图/字段在一个页面:

添加观察员:

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)


NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


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


func keyboardWillHide() {
self.view.frame.origin.y = 0
}


func keyboardWillChange(notification: NSNotification) {


if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if YOURTEXTVIEW.isFirstResponder {
self.view.frame.origin.y = -keyboardSize.height
}
}
}

删除观察员:

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)


NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
我对初学者的两点建议: 在上面的例子中,有人改变坐标,其他人使用“自动调整蒙版”,和其他约束:

就像苹果说的,不要把这3种逻辑混合在一起。 如果你在故事板中有约束,不要尝试改变x/y。

func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
// self.view.frame.origin.y += keyboardSize.height
self.view.frame.origin.y = 0
}
}
}

斯威夫特4:

我有一个问题与最接受的答案,其中隐藏键盘并没有返回视图一直到页面的底部(只是部分)。这对我来说很有效(+为Swift 4更新)。

override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
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)
}


@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}


@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y = 0
}
}
}

Swift 4中的Simpelst方法 enter image description here < / p >

import UIKit


class ViewController: UIViewController, UITextFieldDelegate {


@IBOutlet var myTextField: UITextField!


override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}


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


func keyboardWillShow(notification: NSNotification) {
// let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]
// print("duration",duration)
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight : Int = Int(keyboardSize.height)
print("keyboardWillShow",keyboardHeight)
if let height = UserDefaults.standard.value(forKey: "keyboardHeight") as? (Int) {
moveTextField(myTextField, moveDistance: -height as Int, moveDuration: 0.43, up: true)
}else{
UserDefaults.standard.set(keyboardHeight, forKey: "keyboardHeight")
moveTextField(myTextField, moveDistance: -keyboardHeight, moveDuration: 0.43, up: true)
}
}
}


func keyboardWillHide(notification: NSNotification){
if let height = UserDefaults.standard.value(forKey: "keyboardHeight") as? (Int) {
moveTextField(myTextField, moveDistance: -height as Int, moveDuration: 0.25, up: false)
}
}


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


func moveTextField(_ textField: UITextField, moveDistance: Int, moveDuration: Double, up: Bool) {
let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(moveDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}


}

<强>你也可以上下移动UITextFiled不是整个屏幕(UIView)

.使用此方法
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)

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

验证的答案不是考虑文本字段的位置,有一些错误(双位移,永远不会回到主位置,位移即使texfield是在视图的顶部…)

这个想法是:

  • 获取焦点TextField的Y的绝对位置
  • 来获取键盘高度
  • 来获取屏幕高度
  • 然后计算键盘位置和文本域之间的距离(if <0 ->向上移动视图)
  • 使用UIView。而不是UIView.frame.origin.y -= ..,因为用UIView更容易回到原来的位置。变换= .identity

然后,我们将能够移动视图,只有在必要和特定的位移,以便有聚焦texField刚刚超过键盘

代码如下:

斯威夫特4

class ViewController: UIViewController, UITextFieldDelegate {


var textFieldRealYPosition: CGFloat = 0.0


override func viewDidLoad() {
super.viewDidLoad()


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


// Delegate all textfields


}




@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
if distanceBetweenTextfielAndKeyboard < 0 {
UIView.animate(withDuration: 0.4) {
self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
}
}
}
}




@objc func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.4) {
self.view.transform = .identity
}
}




func textFieldDidBeginEditing(_ textField: UITextField) {
textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
//take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}

我需要移动UIView斯威夫特4当键盘打开和关闭。所有的答案都帮不了我。因为当emojis打开时键盘的高度改变了。所以我的代码是:

@objc func keyboardWillShow(sender: NSNotification) {


if let keyboardFrame: NSValue = sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {


let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height


if(self.oldHeight == keyboardHeight){
self.sendingView.frame.origin.y -= keyboardHeight
self.oldHeight = keyboardHeight
}
else{
self.sendingView.frame.origin.y += self.oldHeight
self.sendingView.frame.origin.y -= keyboardHeight
self.oldHeight = keyboardHeight
}
}
}


@objc func keyboardWillHide(sender: NSNotification) {


if let keyboardFrame: NSValue = sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {


let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height


self.sendingView.frame.origin.y += keyboardHeight


}
}

viewDidLoad()中:

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

self.oldHeight = CGFloat()并定义为类顶部的字段。

__abc0 __abc1。

我解决了黑屏的问题。在验证方案中,敲击后键盘高度变化,导致黑屏。

必须使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey

var isKeyboardAppear = false


override func viewDidLoad() {
super.viewDidLoad()
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)
}


@objc func keyboardWillShow(notification: NSNotification) {
if !isKeyboardAppear {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
isKeyboardAppear = true
}
}


@objc func keyboardWillHide(notification: NSNotification) {
if isKeyboardAppear {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
isKeyboardAppear = false
}
}

当打开键盘时,它100%完美地回答了所有人的更新表视图高度

对于Swift4.2

   override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)


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


@objc func keyboardWillShow(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {


var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
keyboardFrame = self.view.convert(keyboardFrame, from: nil)


var contentInset:UIEdgeInsets = self.tbl.contentInset
contentInset.bottom = keyboardFrame.size.height
self.tbl.contentInset = contentInset
}
}


@objc func keyboardWillHide(notification: NSNotification) {
if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.tbl.contentInset = contentInset
}
}

Swift3.2

    override func viewDidLoad() {
super.viewDidLoad()


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


NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
//self.view.frame.origin.y -= keyboardSize.height
var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
keyboardFrame = self.view.convert(keyboardFrame, from: nil)


var contentInset:UIEdgeInsets = self.tbl.contentInset
contentInset.bottom = keyboardFrame.size.height
self.tbl.contentInset = contentInset


}
}


func keyboardWillHide(notification: NSNotification) {
if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.tbl.contentInset = contentInset
}
}

@Boris的解决方案非常好,但观点有时会被破坏。

为了实现完美的对齐,请使用下面的代码

override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}

功能:

@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}}

而且,

@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y = 0
}
} }

对我有用

override func viewDidLoad() {


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


var isScroll = false




@objc func keyboardWillShow(sender: NSNotification) {
if( !isScroll  ){
self.view.frame.origin.y -= 150
isScroll = true
}
}
@objc func keyboardWillHide(sender: NSNotification) {
if( isScroll  ){
self.view.frame.origin.y += 150
isScroll = false
}
}

我们对KeyboardWillHideNotification的定义做了一些改变。

此解决方案适用于斯威夫特4.2:

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




@objc func keyboardWillShow(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame.origin.y -= keyboardSize.height
}
}


@objc func keyboardWillHide(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame.origin.y += keyboardSize.height
}
}

这个实现(Swift 4)将给你的行为最接近Android的默认行为。Ie:当活动文本域在键盘下时,将视图向上移动,当用户切换到另一个视图时,无需关闭键盘。记住调用settextfielddelegate()。

public class DelegateProxy: NSObject, UITextFieldDelegate {


private static let instance = DelegateProxies()


weak var activeTextField: UITextField?
var offset: CGFloat = 0
weak var vc: UIViewController?
var keyboardHeight: CGFloat = 0


public static func getDelegate(root: UIViewController) -> DelegateProxies {
instance.vc = root
return instance
}


public static func getDelegate() -> DelegateProxies {
return instance
}


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




public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {


self.activeTextField = textField


let globalPointY: CGFloat = (textField.superview?.convert(textField.frame.origin, to: nil).y ?? CGFloat(0)) + textField.frame.height




offset = UIScreen.main.bounds.height - globalPointY


if keyboardHeight > 0 {
vc?.moveViewUp(offsetFromKeyboard: keyboardHeight - offset)
}


return true
}
}




extension UIViewController {


private func setTextFieldDelegates(parentView: UIView) {
for child in parentView.subviews {
setTextFieldDelegates(parentView: child)
(child as? UITextField)?.delegate = DelegateProxies.getDelegate(root: self)
}
}


func registerAutoResizeOnKeyboardAppear(){
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 unregisterAutoResizeOnKeyboard(){
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}


@objc func keyboardWillShow(notification: NSNotification) {


if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let offsetFromKeyboard = keyboardSize.height - DelegateProxies.getDelegate().offset
DelegateProxies.getDelegate().keyboardHeight = keyboardSize.height


moveViewUp(offsetFromKeyboard: offsetFromKeyboard)
}
}


func moveViewUp(offsetFromKeyboard: CGFloat){
print("offset from keyboard: \(offsetFromKeyboard)")


let moveOffset = offsetFromKeyboard + 8


if offsetFromKeyboard > 0 {
self.view.frame.origin.y = -moveOffset
}


if offsetFromKeyboard < 0 && view.frame.origin.y < 0 {
self.view.frame.origin.y += -moveOffset
if self.view.frame.origin.y > 0{
self.view.frame.origin.y = 0
}
}
}


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

斯威夫特4.1

 override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}


@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height   //can adjust as keyboardSize.height-(any number 30 or 40)
}
}
}


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

所以其他答案似乎都不正确。

iOS上的良好行为键盘应该:

  • 键盘改变大小时自动调整大小(YES IT CAN)
  • 动画的速度与键盘相同
  • 使用与键盘相同的曲线进行动画
  • 如果相关,尊重安全区域。
  • 也适用于iPad/Undocked模式

我的代码使用NSLayoutConstraint声明为@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

你也可以使用变换,视图偏移量,....我觉得有了约束就容易多了。它通过在底部设置一个约束来工作,如果你的常量不是0/不是底部,你可能需要修改代码。

代码如下:

// In ViewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)




@objc func keyboardDidChange(notification: Notification) {
let userInfo = notification.userInfo! as [AnyHashable: Any]
let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
// Prevents iPad undocked keyboard.
guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
bottomLayoutConstraint.constant = 0
return
}
UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
UIView.animate(withDuration: animationDuration.doubleValue) {
self.view.layoutIfNeeded()
// Do additional tasks such as scrolling in a UICollectionView
}
}

不是广告、促销或垃圾邮件,只是一个很好的解决方案。我知道这个问题有近30个答案,我很震惊,居然没有人曾经提到过这个漂亮的GitHub项目,它为你做了这一切,甚至更好。所有的答案只是向上移动视图。我刚刚用这个IQKeyboardManager解决了我所有的问题。它有13000多颗恒星。< br > 如果你使用swift

,只需在podfile中添加这个
pod 'IQKeyboardManagerSwift'

然后在你的AppDelegate.swift中做import IQKeyboardManagerSwift

import IQKeyboardManagerSwift


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {


var window: UIWindow?


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


IQKeyboardManager.shared.enable = true // just add this line


return true
}
}

添加行IQKeyboardManager.shared.enable = true以启用它
如果你打算投入生产,这个解决方案是必须的

斯威夫特5.0:

经过4-5个小时的战斗,我得到了一个简单的扩展UIViewController与简单的代码,就像魅力

*当TextField在键盘上方时,视图不应该移动

*不需要设置常量值为NSLayoutConstraint

*无需第三方库

*无需动画代码

*适用于tableview

*这适用于自动布局/自动调整大小

extension UIViewController {
func addKeyboardObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}


func removeKeyboardObserver(){
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}


// This method will notify when keyboard appears/ dissapears
@objc func keyboardNotifications(notification: NSNotification) {


var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard




var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
// Here we will get accurate frame of textField which is selected if there are multiple textfields
frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
txtFieldY = frame.origin.y + frame.size.height
}


if let userInfo = notification.userInfo {
// here we will get frame of keyBoard (i.e. x, y, width, height)
let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let keyBoardFrameY = keyBoardFrame!.origin.y
let keyBoardFrameHeight = keyBoardFrame!.size.height


var viewOriginY: CGFloat = 0.0
//Check keyboards Y position and according to that move view up and down
if keyBoardFrameY >= UIScreen.main.bounds.size.height {
viewOriginY = 0.0
} else {
// if textfields y is greater than keyboards y then only move View to up
if txtFieldY >= keyBoardFrameY {


viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard


//This condition is just to check viewOriginY should not be greator than keyboard height
// if its more than keyboard height then there will be black space on the top of keyboard.
if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
}
}


//set the Y position of view
self.view.frame.origin.y = -viewOriginY
}
}
}

添加这个扩展的UIResponder得到哪个TextField被选中

extension UIResponder {


static weak var responder: UIResponder?


static func currentFirst() -> UIResponder? {
responder = nil
UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
return responder
}


@objc private func trap() {
UIResponder.responder = self
}
}

然后在你的任何ViewController中使用这个

   override func viewWillAppear(_ animated: Bool) {
self.addKeyboardObserver()
}


override func viewWillDisappear(_ animated: Bool) {
self.removeKeyboardObserver()
}

  • func viewWillAppear(_ animated: Bool)中注册这个通知

  • func viewWillDisappear(_ animated:Bool)中注销此通知

    下载演示文件 < / p >

类似于@Boris的答案,但在斯威夫特5中:

override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}


@IBAction func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}


@IBAction func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}

移动视图的原点是一种幼稚的方法。

这里有一个更好的解决方案:当键盘出现时调整视图的高度。

let viewHeight = self.view.frame.height


override func viewDidLoad() {
super.viewDidLoad()


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 let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.height == self.viewHeight{
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - keyboardSize.height)
}


}
}


@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {


self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height + keyboardSize.height)
}
}

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

  1. 我们创建一个发布者来监听通知,显示和隐藏。
  2. 为了演示,我们从通知userInfo中获取键盘帧,并检查当前主动响应器是否包含在其中。如果被覆盖,返回键盘帧高度。如果它没有被覆盖,返回0,我们不想移动帧。对于隐藏通知,我们简单地返回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)
}
< p > 编辑
小心!如果firstResponder在子视图中,你必须计算与整个屏幕对应的帧,以检查它们是否相交。
例子:< / p >
let myViewGlobalFrame = myView.convert(myView.frame, to: parentView)