我使用Swift与iOS编程,我使用这段代码来移动UITextField,但它不起作用。我正确地调用了函数keyboardWillShow,但是文本字段没有移动。我正在使用自动布局。
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self);
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
//let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
var frame = self.ChatField.frame
frame.origin.y = frame.origin.y - keyboardSize.height + 167
self.chatField.frame = frame
println("asdasd")
}
}
下面是一个简单的解决方案,其中文本字段有一个约束将其绑定到底部布局指南。它只是将键盘高度添加到约束常数中。
// This constraint ties the text field to the bottom layout guide
@IBOutlet var textFieldToBottomLayoutGuideConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name:UIKeyboardWillHideNotification, object: nil);
}
func keyboardWillShow(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.textFieldToBottomLayoutGuideConstraint?.constant += keyboardSize.height
}
}
func keyboardWillHide(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.textFieldToBottomLayoutGuideConstraint?.constant -= keyboardSize.height
}
}
对于任何不使用故事板设置布局约束的人。这是一种纯粹的编程方式,让它在Swift 5上工作:
在viewController中定义一个空约束。在这种情况下,我正在构建一个聊天应用程序,在屏幕的最底部有一个包含文本视图的UIView。
var discussionsMessageBoxBottomAnchor: NSLayoutConstraint = NSLayoutConstraint()
在viewDidLoad中为最底部的视图添加约束。在本例中是discussionsMessageBox。另外,为键盘事件添加监听器。
为了正确地初始化约束,您需要首先添加子视图,然后定义约束。
NotificationCenter.default.addObserver(self,
selector: #selector(self.keyboardNotification(notification:)),
name: NSNotification.Name.UIKeyboardWillChangeFrame,
object: nil)
view.addSubview(discussionsMessageBox)
if #available(iOS 11.0, *) {
discussionsMessageBoxBottomAnchor = discussionsMessageBox.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0)
} else {
// Fallback on earlier versions
discussionsMessageBoxBottomAnchor = discussionsMessageBox.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
}
NSLayoutConstraint.activate([ discussionsMessageBoxBottomAnchor ])
定义deinit。
deinit {
NotificationCenter.default.removeObserver(self)
}
接下来添加@JosephLord定义的代码,并对偏移量进行修正。
extension DiscussionsViewController {
@objc func keyboardNotification(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
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 ?? UIView.AnimationOptions.curveEaseInOut.rawValue
let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
if endFrameY >= UIScreen.main.bounds.size.height {
self.discussionsMessageBoxBottomAnchor.constant = 0.0
} else {
//Changed line
self.discussionsMessageBoxBottomAnchor.constant = -1 * (endFrame?.size.height ?? 0.0)
}
UIView.animate(
withDuration: duration,
delay: TimeInterval(0),
options: animationCurve,
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
}
我的做法如下:
class SignInController: UIViewController , UITextFieldDelegate {
@IBOutlet weak var scrollView: UIScrollView!
// outlet declartion
@IBOutlet weak var signInTextView: UITextField!
var kbHeight: CGFloat!
/**
*
* @method viewDidLoad
*
*/
override func viewDidLoad() {
super.viewDidLoad()
self.signInTextView.delegate = self
}// end viewDidLoad
/**
*
* @method viewWillAppear
*
*/
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}// end viewWillAppear
/**
*
* @method viewDidAppear
*
*/
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}// end viewDidAppear
/**
*
* @method viewWillDisappear
*
*/
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
/**
*
* @method textFieldShouldReturn
* retun the keyboard value
*
*/
// MARK -
func textFieldShouldReturn(textField: UITextField) -> Bool {
signInTextView.resignFirstResponder()
return true;
}// end textFieldShouldReturn
// MARK - keyboardWillShow
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
kbHeight = keyboardSize.height
self.animateTextField(true)
}
}
}// end keyboardWillShow
// MARK - keyboardWillHide
func keyboardWillHide(notification: NSNotification) {
self.animateTextField(false)
}// end keyboardWillHide
// MARK - animateTextField
func animateTextField(up: Bool) {
var movement = (up ? -kbHeight : kbHeight)
UIView.animateWithDuration(0.3, animations: {
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
})
}// end animateTextField
/**
*
* @method didReceiveMemoryWarning
*
*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}// end didReceiveMemoryWarning
}// end SignInController
管理键盘的完整代码。
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
guard let userInfo = notification.userInfo else {return}
guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return}
let keyboardFrame = keyboardSize.cgRectValue
if self.view.bounds.origin.y == 0{
self.view.bounds.origin.y += keyboardFrame.height
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.bounds.origin.y != 0 {
self.view.bounds.origin.y = 0
}
}
如果你正在使用自动布局,我假设你已经设置了底部空间为Superview约束。如果是这种情况,您只需更新约束的值。这是你如何用一点动画来做到这一点。
func keyboardWasShown(notification: NSNotification) {
let info = notification.userInfo!
let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
UIView.animateWithDuration(0.1, animations: { () -> Void in
self.bottomConstraint.constant = keyboardFrame.size.height + 20
})
}
添加硬编码的20只是为了将文本框弹出到键盘上方一点。否则键盘的上边距和文本框的下边距将会接触。
当键盘关闭时,将约束的值重置为原始值。
这是一个通用的解决方案,为所有的TextField
步骤,
1)创建一个由其他ViewController扩展的通用ViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= getMoveableDistance(keyboarHeight: keyboardSize.height)
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
//get the distance to move up the main view for the focus textfiled
func getMoveableDistance(keyboarHeight : CGFloat) -> CGFloat{
var y:CGFloat = 0.0
if let activeTF = getSelectedTextField(){
var tfMaxY = activeTF.frame.maxY
var containerView = activeTF.superview!
while containerView.frame.maxY != self.view.frame.maxY{
let contViewFrm = containerView.convert(activeTF.frame, to: containerView.superview)
tfMaxY = tfMaxY + contViewFrm.minY
containerView = containerView.superview!
}
let keyboardMinY = self.view.frame.height - keyboarHeight
if tfMaxY > keyboardMinY{
y = (tfMaxY - keyboardMinY) + 10.0
}
}
return y
}
2)创建UIViewController和当前激活的TextField的扩展
//get active text field
扩展 UIViewController {
func getSelectedTextField() -> UITextField?{
let totalTextFields = getTextFieldsInView(view: self.view)
for textField in totalTextFields{
if textField.isFirstResponder{
return textField
}
}
return nil
}
func getTextFieldsInView(view: UIView) -> [UITextField] {
var totalTextFields = [UITextField]()
for subview in view.subviews as [UIView] {
if let textField = subview as? UITextField {
totalTextFields += [textField]
} else {
totalTextFields += getTextFieldsInView(view: subview)
}
}
return totalTextFields
}
}