小言_互联网的博客

iOS 解决键盘遮挡输入框问题,输入框随键盘弹起上移,切换输入法时动态调整 (Swift)

645人阅读  评论(0)

最近在项目中需要解决苹果系统输入法遮挡输入框的问题,预期结果为:

  1. 若键盘弹出后会遮挡输入框,则输入框随键盘弹起上移,输入法切换时输入框始终保持在距键盘上方 4pt 处;
  2. 若键盘弹出后不会遮挡输入框,但切换输入法后会遮挡输入框,则输入框需要在切换后上移,随后输入法切换时输入框始终保持在键盘上方 4pt 处。

效果示意:

一. 背景

开发环境:iOS14.2 + Xcode v12.2 + Swift5
设备:iPhoneSE(其他机型测试有效)
页面采用自动布局

二. 实现方式

在viewWillAppear中添加键盘弹出、收起、frame变化的通知

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

    // 键盘弹出监听,解决键盘挡住输入框的问题
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardWillAppear),
                                           name: UIResponder.keyboardWillShowNotification,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardHasAppear),
                                           name: UIResponder.keyboardDidShowNotification,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardWillDisappear),
                                           name: UIResponder.keyboardWillHideNotification,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardFrameDidChange),
                                           name: UIResponder.keyboardDidChangeFrameNotification,
                                           object: nil)
}

(相关链接:iOS键盘通知

添加成员变量:

private var keyboardFlag: Int = 0 // 键盘弹起情况,收起=0
private var deltaHeight: CGFloat = 0 // 键盘与输入框间距
private var nameFieldBottomHeight: CGFloat = 0 // 输入框底部到页面底部距离
private var transformDistance: CGFloat = 0 // 页面移动距离

实现 keyboardWillAppear:

@objc
func keyboardWillAppear(noti: Notification) {
   
    // 获得软键盘的高
    let keyboardSize = (noti.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
    let keyboardHeight = keyboardSize?.height

    // 计算输入框和软键盘的高度差
    /* nickNameEditView.containerView:输入框 */
    let rect = self.nickNameEditView.containerView
        .convert(self.nickNameEditView.containerView.bounds,
                 to: self.view) // 将rect由rect所在视图转换到目标视图view中,返回在目标视图view中的rect

    self.nameFieldBottomHeight = self.view.bounds.height - (rect.origin.y + rect.size.height) // 输入框底部到页面底部距离
    self.deltaHeight = (keyboardHeight ?? 0) - self.nameFieldBottomHeight // 键盘高度 与 输入框底部到页面底部 距离差

    if self.keyboardFlag == 0, self.deltaHeight > 0 {
    // 键盘原来是收起的,且遮挡输入框
        self.pageContainerView.transform = CGAffineTransform(a: 1, b: 0, c: 0, d: 1,
                                                             tx: 0, ty: -self.deltaHeight - 4)
        self.transformDistance = -self.deltaHeight - 4
        /* -4:为了使键盘距离输入框底部距离为4pt,该值可改 */
        /* pageContainerView:需要移动的控件,包成一个view */
    }
}

实现keyboardHasAppear:

@objc
func keyboardHasAppear() {
   
    self.keyboardFlag = 1 // 键盘已弹出
}

实现keyboardWillDisappear:

@objc
func keyboardWillDisappear() {
   
    if self.keyboardFlag == 0 {
   
		// 软键盘收起的时候恢复原始偏移
		self.pageContainerView.transform = CGAffineTransform.identity
		self.transformDistance = 0
	}
}

实现 keyboardFrameDidChange,解决切换输入法动态调整:

@objc
func keyboardFrameDidChange(noti: Notification) {
   
    // 获得软键盘的高
    let keyboardSize = (noti.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
    let keyboardHeight = keyboardSize?.height

    // 计算输入框和软键盘的高度差
    self.deltaHeight = (keyboardHeight ?? 0) - (self.nameFieldBottomHeight + self.transformDistance)

    // 键盘在弹出的情况下如果frame有变化就改变输入框位置
    if self.keyboardFlag == 1 {
   
        // 如果页面之前没有上移,键盘遮挡输入框,页面上移; 页面之前有上移,输入框下降到键盘上方4pt处
        if (self.transformDistance == 0 && self.deltaHeight > 0) || (self.transformDistance != 0) {
   
            self.pageContainerView.transform = CGAffineTransform(a: 1, b: 0, c: 0, d: 1,
                                                                 tx: 0, ty: -self.deltaHeight - 4)
            self.transformDistance = -self.deltaHeight - 4
        }
    }
}

点击空白区域收取键盘:

// 收起键盘
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
   
    if self.nickNameEditView.nameTextField.isFirstResponder {
   
        self.keyboardFlag = 0
        self.nickNameEditView.nameTextField.resignFirstResponder()
    }
}

在 viewWillDisappear 中移除通知:

override func viewWillDisappear(_ animated: Bool) {
   
    super.viewWillDisappear(animated)
    
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
}

End.


由于我水平尚浅,计算和实现方法可能有很多不足,有任何问题欢迎评论交流~


转载:https://blog.csdn.net/fusy0714/article/details/109076048
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场