仅在键盘覆盖输入字段时才向上移动视图

问题描述 投票:135回答:25

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

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

我用过这段代码我找到了here

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
}
ios swift keyboard xcode6
25个回答
198
投票

你的问题在this document by Apple得到了很好的解释。此页面上的示例代码(位于Listing 4-1)完全符合您的需要,它将仅在当前编辑应位于键盘下时滚动您的视图。您只需要将所需的控件放在scrollViiew中。唯一的问题是这是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并在初始化方法中设置正确的委托:ex:

self.you_text_field.delegate = self

并记得在退出时在viewInit和registerForKeyboardNotifications上调用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
}

0
投票

阅读Apple提供的文档和之前的帖子后,这是我的版本。我注意到的一件事是当键盘覆盖时没有处理textView。遗憾的是,Apple的文档无法正常工作,因为无论出于何种原因,在调用textViewDidBeginEditing之后调用键盘。我通过调用一个中央方法来检查键盘是否显示以及是否正在编辑textView或textField。这样,只有当BOTH条件存在时才会触发该过程。

textViews的另一个要点是它们的高度可能会使键盘剪切textView的底部,如果在视图中的左上角点则不会调整。因此,我编写的代码实际上采用任何textView或textField的屏幕引用的Bottom-Left点,并查看它是否落在所呈现键盘的屏幕引用坐标中,暗示键盘覆盖了它的某些部分。

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
}

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

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

它遍历每个textView和textField以设置委托以进行处理

self.automaticallyAdjustsScrollViewInsets = false

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

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

0
投票

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

首先在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() } } 中调用以下方法

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) } IBOutletUIView的顶级约束像这样:(这里UIViewcontrollerUIView的子视图,这意味着你应该有所有UIScrollViewUIScrollView

subViews

另一个变量如跟随并添加一个委托,即@IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!

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) } 中的所有UITextFields

祝好运!


0
投票

Swift 3语法:

UIStoryboard

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


0
投票

首先声明一个变量来标识您的活动UITextField。

步骤1:-

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() } 一样?

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

var activeTextField: UITextField

第3步: -

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

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)

0
投票

对于swift 4.2。

这适用于任何形式。不需要scrollview。不要忘记设置委托。

制作一个uitextfield变种

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
}

在你的viewdidload中

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
}

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


-1
投票

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

好 。首先确认UITextFieldDelegate协议

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

然后实现该功能

class YourClass:UITextFieldDelegate

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


-1
投票

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

func textFieldDidBeginEditing(textField: UITextField!) {

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

然后在viewDidLoad中:

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)

-1
投票

斯威夫特3

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

-1
投票

被接受的anwser几乎是完美的。但我需要使用@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 } 而不是UIKeyboardFrameEndUserInfoKey,因为后者返回keyborad高度0.并将最高点更改为底部而不是原点。

UIKeyboardFrameBeginUserInfoKey,

-1
投票

Swift 4更新了我的解决方案

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

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

127
投票

这是我的2美分:

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

非常容易安装Swift或Objective-C。

它是如何工作的:

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

pod 'IQKeyboardManagerSwift'

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

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

    IQKeyboardManager.sharedManager().enable = true
    // For Swift 4, use this instead
    // IQKeyboardManager.shared.enable = true


    return true
    }
}

这就是全部。简单!


-1
投票

斯威夫特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 }) } } } 键盘与动画

UITextField

enter image description here

-1
投票

Swift 4.2

如果它的位置在键盘下面,我的解决方案将(垂直)将视图置于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) } 的中心。

第1步:创建新的swift文件并复制粘贴UITextField类。 第2步:在Interface Builder中将其设置为最顶级UIViewWithKeyboard的自定义类。

UIView

-1
投票

重写为快速4.2

在ViewDidLoad ..

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

剩余功能

 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)

-1
投票

对于Swift 4.2

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

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

为UIDevice创建扩展

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
}

在viewDidLoad上添加NotificationObserver

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

选择

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

18
投票

我发现对我来说完美的工作是:

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。


6
投票

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

我有一个类似的问题,发现一个非常简单的解决方案,而不使用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)时

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


5
投票

只需使用此扩展名即可在键盘出现时移动任何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)
    }
}

然后在viewdidload中将视图绑定到键盘

UiView.bindToKeyboard()

4
投票

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


3
投票

Swift 4(**已更新),附加**

  1. 在一个容器中添加按钮
  2. 使用IBOutlet containerBtmConstrain连接容器的底部约束
  3. ionViewDidLoad qazxsw poi
  4. 添加以下扩展名 self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain self.watchForKeyboard()

1
投票

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

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!
        let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

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

虽然activeField的起源可能在键盘上方,但maxY可能不会...

我会为activeField创建一个'max'点并检查它是否在键盘Rect中。


1
投票

我使用SwiftLint,它对接受的答案的格式有一些问题。特别:

在冒号之前没有空格,没有强制转换,更喜欢UIEdgeInsets(顶部:等等...而不是UIEdgeInsetsMake。

所以这里是Swift 3的更新

if (!CGRectContainsPoint(aRect, activeField!.frame.origin))
© www.soinside.com 2019 - 2024. All rights reserved.