我有一个UIScrollView
和一个UITextView
,就像在任何消息/聊天应用中一样,当UIScrollView
向下滚动时,键盘也会被交互式拖动。
我需要在滚动UIScrollView
时检测键盘高度,我尝试了UIKeyboardWillChangeFrame
观察者,但是在释放滚动点按后会调用此事件。
在不知道键盘高度的情况下,我无法更新UITextView
底部约束,并且我在键盘和底部视图之间得到了一个间隙@screenshot。
同时附加来自Viber的屏幕截图,当从滚动条拖动键盘时对齐底部栏也可以在WhatsApp中看到。
答案 0 :(得分:1)
从iOS 10开始,当NSNotification
,UIScrollView
以交互方式拖动键盘时,Apple不提供UIKeyboardWillChangeFrame
观察员来检测帧更改只有一次释放水龙头才会发现UIKeyboardDidChangeFrame
。
无论如何,在查看DAKeyboardControl库后,我有意在UIScrollView.UIPanGestureRecognizer
附加UIViewController
,因此生成的所有手势事件都将在UIViewController
中处理同样。拧了好几个小时后,我开始工作,这里是所有必需的代码:
class ViewController: UIViewController, UIGestureRecognizerDelegate {
fileprivate let collectionView = UICollectionView(frame: .zero)
private let bottomView = UIView()
fileprivate var bottomInset: NSLayoutConstraint!
// This holds height of keypad
private var maxKeypadHeight: CGFloat = 0 {
didSet {
self.updateCollectionViewInsets(maxKeypadHeight + self.bottomView.frame.height)
self.bottomInset.constant = -maxKeypadHeight
}
}
private var isListeningKeypadChange = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keypadWillChange(_:)), name: .UIKeyboardWillChangeFrame, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keypadWillShow(_:)), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keypadWillHide(_:)), name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keypadDidHide), name: .UIKeyboardDidHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
func keypadWillShow(_ notification: Notification) {
guard !self.isListeningKeypadChange, let userInfo = notification.userInfo as? [String : Any],
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval,
let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue
else {
return
}
self.maxKeypadHeight = value.cgRectValue.height
let options = UIViewAnimationOptions.beginFromCurrentState.union(UIViewAnimationOptions(rawValue: animationCurve))
UIView.animate(withDuration: animationDuration, delay: 0, options: options, animations: { [weak self] in
self?.view.layoutIfNeeded()
}, completion: { finished in
guard finished else { return }
// Some delay of about 500MS, before ready to listen other keypad events
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.beginListeningKeypadChange()
}
})
}
func handlePanGestureRecognizer(_ pan: UIPanGestureRecognizer) {
guard self.isListeningKeypadChange, let windowHeight = self.view.window?.frame.height else { return }
let barHeight = self.bottomView.frame.height
let keypadHeight = abs(self.bottomInset.constant)
let usedHeight = keypadHeight + barHeight
let dragY = windowHeight - pan.location(in: self.view.window).y
let newValue = min(dragY < usedHeight ? max(dragY, 0) : dragY, self.maxKeypadHeight)
print("Old: \(keypadHeight) New: \(newValue) Drag: \(dragY) Used: \(usedHeight)")
guard keypadHeight != newValue else { return }
self.updateCollectionViewInsets(newValue + barHeight)
self.bottomInset.constant = -newValue
}
func keypadWillChange(_ notification: Notification) {
if self.isListeningKeypadChange, let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {
self.maxKeypadHeight = value.cgRectValue.height
}
}
func keypadWillHide(_ notification: Notification) {
guard let userInfo = notification.userInfo as? [String : Any] else { return }
self.maxKeypadHeight = 0
var options = UIViewAnimationOptions.beginFromCurrentState
if let animationCurve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt {
options = options.union(UIViewAnimationOptions(rawValue: animationCurve))
}
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval
UIView.animate(withDuration: duration ?? 0, delay: 0, options: options, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
func keypadDidHide() {
self.collectionView.panGestureRecognizer.removeTarget(self, action: nil)
self.isListeningKeypadChange = false
if (self.maxKeypadHeight != 0 || self.bottomInset.constant != 0) {
self.maxKeypadHeight = 0
}
}
private func beginListeningKeypadChange() {
self.isListeningKeypadChange = true
self.collectionView.panGestureRecognizer.addTarget(self, action: #selector(self.handlePanGestureRecognizer(_:)))
}
fileprivate func updateCollectionViewInsets(_ value: CGFloat) {
let insets = UIEdgeInsets(top: 0, left: 0, bottom: value + 8, right: 0)
self.collectionView.contentInset = insets
self.collectionView.scrollIndicatorInsets = insets
}
}
答案 1 :(得分:0)
您可以尝试这种方式,我已在我的项目中实施。希望它会对你有所帮助。
@IBOutlet weak var constant_ViewBottom: NSLayoutConstraint! // 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
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)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(_ notification: NSNotification){
if let keyboardRectValue = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
let keyboardHeight = keyboardRectValue.height
print("keyboardHeight:=\(keyboardHeight)")
constant_ViewBottom.constant = keyboardHeight
self.view.layoutIfNeeded()
}
}
func keyboardWillHide(_ notification: NSNotification){
constant_ViewBottom.constant = 0.0
self.view.layoutIfNeeded()
}
答案 2 :(得分:0)
看起来你有一个底部约束的错误常数。 尝试每次重置底部约束并设置新的高度值
func keyboardDidChangeFrame(notification: Notification) {
if let userInfo = notification.userInfo {
if let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let duration: TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions().rawValue
let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
if endFrame.origin.y >= UIScreen.main.bounds.size.height {
self.inputBarBottomSpacing.constant = 0
} else {
//the most important logic branch, reset current bottom constant constraint value
if self.inputBarBottomSpacing.constant != 0 {
self.inputBarBottomSpacing.constant = 0
}
self.inputBarBottomSpacing.constant = -endFrame.size.height
}
UIView.animate(withDuration: duration, delay: TimeInterval(0), options: animationCurve, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
}
答案 3 :(得分:0)
您只需添加此广告连结:
IOTEvent.State .attrs.EventTime DataEvent.Model DataEvent.DataType DataEvent.DataValue
1: PowerOn 2017-02-27T18:33:58 NA NA NA
2: NA 2017-02-28T08:59:03 1 1 0301
3: NA 2017-02-28T08:59:13 1 1 0401
然后在 AppDelegate.swift 中添加:
pod 'IQKeyboardManagerSwift'
import IQKeyboardManagerSwift
函数中的a
didFinishLaunchingWithOptions
这很简单。