我有一个pageviewcontroller,它水平滚动,显示问题和答案。
pageviewcontroller的contentView填充了一个scrollview,其中有一些堆栈视图,其中一个有一个textView,供用户输入。
当用户点击textView时,键盘会弹出,有时会覆盖textView。当我尝试垂直滚动时,正如我希望滚动视图允许的那样,滚动视图没有响应,我只能水平滚动到下一页视图。
问题在于,当用户点击文本视图后弹出键盘时,文本视图可能隐藏在键盘下方,因此用户无法看到他键入的内容。我想点击键盘时向上滚动视图,这样用户就可以看到输入内容了。
答案 0 :(得分:0)
这叫做“键盘管理” 你必须:
1)设置键盘的观察者显示和键盘消失动作
2)键盘出现时更新底部约束。
3)当键盘消失时再次更新。
4)当视图消失时,删除观察者。
分步说明,例如:Move view with keyboard using Swift
但我的建议是更新约束,而不是更新,就像在教学中一样。或者,也许,您可以为内容设置偏移量
答案 1 :(得分:0)
您应该在堆栈视图中设置底部约束 然后按照以下方式控制你的类:
class yourClassViewController: UIViewController {
// MARK: Properties
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
然后在你的viewDidLoad方法中写这样:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardNotification(notification:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
// Do any additional setup after loading the view.
}
以下:
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func keyboardNotification(notification: NSNotification) {
if let userInfo = notification.userInfo {
let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
let endFrameY = endFrame?.origin.y ?? 0
let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrameY >= UIScreen.main.bounds.size.height {
self.bottomConstraint?.constant = 0.0
} else {
self.bottomConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animate(withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
对于touchsBegan方法中的消失键盘你应该这样写:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
答案 2 :(得分:0)
使用通知观察者处理键盘显示和隐藏事件:
// keyboard will show
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowAction(_:)), name: .UIKeyboardWillShow, object: nil)
// keyboard will hide
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideAction(_:)), name: .UIKeyboardWillHide, object: nil)
键盘即将出现时,您可以执行以下操作:
// keyboard will show action
@objc private func keyboardWillShowAction(_ notification: NSNotification) {
currentScrollViewOffset = scrollView.contentOffset
let keyboardFrame = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue
let keyboardHeight = keyboardFrame?.cgRectValue.height
let padding: CGFloat = 32
// if text field view would be obstructed by keyboard, apply minimum-needed scroll view offset
if activeTextFieldMaxYOnScreen! > (UIScreen.main.bounds.height - keyboardHeight! - padding) {
let temporaryOffset = activeTextFieldMaxYOnScreen! - (UIScreen.main.bounds.height - (keyboardHeight! + padding))
scrollView.setContentOffset(CGPoint(x: 0, y: currentScrollViewOffset.y + temporaryOffset), animated: true)
}
scrollView.addGestureRecognizer(tapToDismissKeyboard)
scrollView.isScrollEnabled = false
}
然后在键盘解除时恢复:
// keyboard will hide action
@objc private func keyboardWillHideAction(_ notification: NSNotification) {
scrollView.setContentOffset(currentScrollViewOffset, animated: true)
scrollView.removeGestureRecognizer(tapToDismissKeyboard)
scrollView.isScrollEnabled = true
}
在deinit
方法中删除观察者也是一种很好的做法:
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
请注意,currentScrollViewOffset
和activeTextFieldMaxYOnScreen
是视图控制器的实例属性。要获取activeTextFieldMaxYOnScreen
值,您可以从文本字段委托中获取它:
// text field should begin editing
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
// convert text field line's max-y to perceived max-y on the screen
let line = textField.viewWithTag(123)
activeTextFieldMaxYOnScreen = (line?.convert((line?.bounds.origin)!, to: nil).y)! + (line?.frame.height)!
return true
}