Swift - 使用 UIKeyboardWillChangeFrame 时关闭键盘并调用 TouchUpInside 按钮同时不起作用
Swift - Dismiss Keyboard and call TouchUpInside Button Simultaneously not working when using UIKeyboardWillChangeFrame
我正在使用 swift 并且 TouchUpInside 有问题:如果我正在使用 UIKeyboardWillChangeFrame 或 UIKeyboardWillShow/UIKeyboardWillHide,& 键盘正在显示,& 我试图按下的按钮在最初显示键盘时的键盘。 (如果我向下滚动到按钮直到可见并按下,则不会调用 touchUpInside)。
无论键盘是否显示,TouchDown 似乎都能正常工作,但不会调用 TouchUpInside。如果最初显示键盘时按钮位于键盘顶部上方,则 TouchUpInside 有效。我正在使用 keyboardNotification 将视图的高度设置在我的 scrollView 下面,以便在显示键盘时提升我的 scrollView。据我所知,通常只有当按钮是 scrollView 中的最后一个元素时(因此当显示键盘时可能位于键盘后面)。
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var saveButton: UIButton!
@IBAction func saveTouchUpInside(_ sender: UIButton) {
print("touchupinside = does not work")
}
@objc func saveTouchDown(notification:NSNotification){
print("touchdown = works")
}
viewWillAppear:
textField.delegate = self
NotificationCenter.default.addObserver(self,selector:#selector(self.keyboardNotification(notification:)),name:
NSNotification.Name.UIKeyboardWillChangeFrame,object: nil)
self.saveButton.addTarget(self, action:#selector(ViewController.saveTouchDown(notification:)), for: .touchDown)
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.keyboardHeightLayoutConstraint?.constant = 0.0
} else {
self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animate(withDuration: duration, delay: TimeInterval(0),options: animationCurve, animations: { self.view.layoutIfNeeded() }, completion: nil)
}
}
我想关闭键盘并同时调用 saveTouchUpInside,而不使用 TouchDown。
我将键盘交互抽象为一个单独的 class,这样我的控制器就不会变得臃肿(也遵循 separation of concerns
)。这是我使用的键盘管理器 class。
import UIKit
/**
* To adjust the scroll view associated with the displayed view to accommodate
* the display of keyboard so that the view gets adjusted accordingly without getting hidden
*/
class KeyboardManager {
private var scrollView: UIScrollView
/**
* -parameter scrollView: ScrollView that need to be adjusted so that it does not get clipped by the presence of the keyboard
*/
init(scrollView: UIScrollView) {
self.scrollView = scrollView
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(adjustForKeyboard),
name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self,
selector: #selector(adjustForKeyboard),
name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
}
/**
* Indicates that the on-screen keyboard is about to be presented.
* -parameter notification: Contains animation and frame details on the keyboard
*
*/
@objc func adjustForKeyboard(notification: Notification) {
guard let containedView = scrollView.superview else { return }
let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboardViewEndFrame = containedView.convert(keyboardScreenEndFrame, to: containedView.window)
let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
let rawAnimationCurveValue = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue
UIView.animate(withDuration: TimeInterval(truncating: duration),
delay: 0,
options: [UIView.AnimationOptions(rawValue: rawAnimationCurveValue)],
animations: {
if notification.name == UIResponder.keyboardWillHideNotification {
self.scrollView.contentInset = UIEdgeInsets.zero
} else {
self.scrollView.contentInset = UIEdgeInsets(top: 0,
left: 0,
bottom: keyboardViewEndFrame.height,
right: 0)
}
self.scrollView.scrollIndicatorInsets = self.scrollView.contentInset
},
completion: nil)
}
deinit {
let notificationCenter = NotificationCenter.default
notificationCenter.removeObserver(self)
}
}
它的用法是这样的
- 创建对键盘管理器的引用
private var keyboardManager: KeyboardManager!
- 并在
viewDidLoad
中分配键盘管理器 class,其中 self.scrollView
是您正在使用的滚动视图
self.keyboardManager = KeyboardManager(scrollView: self.scrollView)
这应该可以解决这个问题。如果这不起作用,一个示例项目可能有助于深入研究它。
我正在使用 swift 并且 TouchUpInside 有问题:如果我正在使用 UIKeyboardWillChangeFrame 或 UIKeyboardWillShow/UIKeyboardWillHide,& 键盘正在显示,& 我试图按下的按钮在最初显示键盘时的键盘。 (如果我向下滚动到按钮直到可见并按下,则不会调用 touchUpInside)。
无论键盘是否显示,TouchDown 似乎都能正常工作,但不会调用 TouchUpInside。如果最初显示键盘时按钮位于键盘顶部上方,则 TouchUpInside 有效。我正在使用 keyboardNotification 将视图的高度设置在我的 scrollView 下面,以便在显示键盘时提升我的 scrollView。据我所知,通常只有当按钮是 scrollView 中的最后一个元素时(因此当显示键盘时可能位于键盘后面)。
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var saveButton: UIButton!
@IBAction func saveTouchUpInside(_ sender: UIButton) {
print("touchupinside = does not work")
}
@objc func saveTouchDown(notification:NSNotification){
print("touchdown = works")
}
viewWillAppear:
textField.delegate = self
NotificationCenter.default.addObserver(self,selector:#selector(self.keyboardNotification(notification:)),name:
NSNotification.Name.UIKeyboardWillChangeFrame,object: nil)
self.saveButton.addTarget(self, action:#selector(ViewController.saveTouchDown(notification:)), for: .touchDown)
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.keyboardHeightLayoutConstraint?.constant = 0.0
} else {
self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
}
UIView.animate(withDuration: duration, delay: TimeInterval(0),options: animationCurve, animations: { self.view.layoutIfNeeded() }, completion: nil)
}
}
我想关闭键盘并同时调用 saveTouchUpInside,而不使用 TouchDown。
我将键盘交互抽象为一个单独的 class,这样我的控制器就不会变得臃肿(也遵循 separation of concerns
)。这是我使用的键盘管理器 class。
import UIKit
/**
* To adjust the scroll view associated with the displayed view to accommodate
* the display of keyboard so that the view gets adjusted accordingly without getting hidden
*/
class KeyboardManager {
private var scrollView: UIScrollView
/**
* -parameter scrollView: ScrollView that need to be adjusted so that it does not get clipped by the presence of the keyboard
*/
init(scrollView: UIScrollView) {
self.scrollView = scrollView
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(adjustForKeyboard),
name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self,
selector: #selector(adjustForKeyboard),
name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
}
/**
* Indicates that the on-screen keyboard is about to be presented.
* -parameter notification: Contains animation and frame details on the keyboard
*
*/
@objc func adjustForKeyboard(notification: Notification) {
guard let containedView = scrollView.superview else { return }
let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboardViewEndFrame = containedView.convert(keyboardScreenEndFrame, to: containedView.window)
let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
let rawAnimationCurveValue = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue
UIView.animate(withDuration: TimeInterval(truncating: duration),
delay: 0,
options: [UIView.AnimationOptions(rawValue: rawAnimationCurveValue)],
animations: {
if notification.name == UIResponder.keyboardWillHideNotification {
self.scrollView.contentInset = UIEdgeInsets.zero
} else {
self.scrollView.contentInset = UIEdgeInsets(top: 0,
left: 0,
bottom: keyboardViewEndFrame.height,
right: 0)
}
self.scrollView.scrollIndicatorInsets = self.scrollView.contentInset
},
completion: nil)
}
deinit {
let notificationCenter = NotificationCenter.default
notificationCenter.removeObserver(self)
}
}
它的用法是这样的
- 创建对键盘管理器的引用
private var keyboardManager: KeyboardManager!
- 并在
viewDidLoad
中分配键盘管理器 class,其中self.scrollView
是您正在使用的滚动视图
self.keyboardManager = KeyboardManager(scrollView: self.scrollView)
这应该可以解决这个问题。如果这不起作用,一个示例项目可能有助于深入研究它。