简体   繁体   中英

Clicking on second UITextField with keyboard already displayed moves content incorrectly

EDIT: Added the methods that were requested.

UPDATE: When I click on input 1 the keyboardwillchange callback is called once. When I click on the 2nd input without first dismissing the keyboard, the keyboardwillchange callback is called TWICE for some reason. Additionally, I noticed my code is still calculating the correct frames. However, it seems xcode is ignoring that or just overriding and putting things back to how they were originally constructed.

I have a screen with some image content at the top and 2 text fields and a text view at the bottom half. The inputs are in a stack view. Whenever I click on a text field/view I move the stack view up far enough so all inputs are visible. When I dismiss the keyboard the stack view goes back to it's original location. This works great! When I click on one text field (regular keyboard) and then click on the other text field (number pad) my stack view goes back to the original location when it shouldn't move at all. To try and fix this I put in some boolean that tracks if the keyboard is displayed and use it to prevent my UIKeyboardWillShow method from doing anything.

What is Xcode 9.1/Swift 4 doing that I can stop from happening?

Side note: I tried using IQKeyboardManager, but it doesn't seem to allow me to prevent the top image content from moving too much.

My relevant code:

class MoodEntryVC: UIViewController, UITextFieldDelegate, UITextViewDelegate {

@IBOutlet weak var questionsStackView: UIStackView!
@IBOutlet weak var hoursTextField: UITextField!
@IBOutlet weak var locationTextField: UITextField!
@IBOutlet weak var otherInfoTextView: UITextView!
@IBOutlet weak var headerBarView: UIView!
@IBOutlet weak var bgHeaderView: UIImageView!

var currentTextField: UITextField?
var currentTextView: UITextView?
var currentBGHeaderFrame: CGRect!
var currentQuestionsStackFrame: CGRect!
var currentFieldEditing: FieldType!
var keyboardVisible: Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    hideKeyboardWhenTappedAround2()

    locationTextField.delegate = self
    hoursTextField.delegate = self
    otherInfoTextView.delegate = self

    currentBGHeaderFrame = bgHeaderView.frame
    currentQuestionsStackFrame = questionsStackView.frame

    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)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}

fileprivate func moveQuestionsAndBGHeader(_ newTopY: CGFloat, _ bgNewTopY: CGFloat) {
    UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        let newRect = CGRect(x: self.questionsStackView.frame.origin.x, y: newTopY, width: self.questionsStackView.bounds.width, height: self.questionsStackView.bounds.height)
        self.questionsStackView.frame = newRect
        self.bgHeaderView.frame = CGRect(x: self.bgHeaderView.frame.origin.x, y: bgNewTopY, width: self.bgHeaderView.bounds.width, height: self.bgHeaderView.bounds.height)
    }, completion: nil)
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    UIView.animate(withDuration: 1.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
        textField.resignFirstResponder()
    }, completion: nil)
    return true
}

@objc func keyboardDidShow(_ notification: NSNotification) {
    keyboardVisible = true
}

@objc func keyboardWillChangeFrame(_ notification: NSNotification) {
    print("keyboard will change")
}

@objc func keyboardWillShow(_ notification: NSNotification) {        
    if keyboardVisible {
        return
    }

    // Get keyboard sizing
    let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

    // Get data entry view sizing
    let topY = questionsStackView.frame.origin.y
    let bottomY = questionsStackView.frame.height + topY
    let newTopY = endFrame.origin.y - 10 - questionsStackView.frame.height

    // Get bgHeaderView sizing
    let bgTopY = bgHeaderView.frame.origin.y
    let bgBottomY = bgHeaderView.frame.height + bgTopY
    let gapToDataEntry = topY - bgBottomY
    let bgNewTopY = newTopY - gapToDataEntry - bgHeaderView.frame.height

    // This moves the stack view to the correct location above the keyboard
    moveQuestionsAndBGHeader(newTopY, bgNewTopY)
}

@objc func keyboardWillHide(_ notification: NSNotification) {
    UIView.animate(withDuration: 1.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
       self.moveQuestionsAndBGHeader(self.currentQuestionsStackFrame.origin.y, self.currentBGHeaderFrame.origin.y)
         self.view.endEditing(true)
    }, completion: nil)
    keyboardVisible = false
}

Thank you!

try adding this method

func textFieldDidEndEditing(textField: UITextField) {
    view.endEditing(true)
}

when first textfield will become de active then keyboard will hide. similarly when other textfield will become active then keyboard will show.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM