我使用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")
}
}
另一个解决方案,不依赖于自动布局,约束或任何出口。您所需要的是滚动视图中的字段。
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func makeSpaceForKeyboard(notification: NSNotification) {
let info = notification.userInfo!
let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double
if notification.name == UIKeyboardWillShowNotification {
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height - keyboardHeight
self.view.frame = frame
})
} else {
UIView.animateWithDuration(duration, animations: { () -> Void in
var frame = self.view.frame
frame.size.height = frame.size.height + keyboardHeight
self.view.frame = frame
})
}
}
我已采取以下方式:
当textfield superview为view时,这很有用
class AdminLoginViewController: UIViewController,
UITextFieldDelegate{
@IBOutlet weak var txtUserName: UITextField!
@IBOutlet weak var txtUserPassword: UITextField!
@IBOutlet weak var btnAdminLogin: UIButton!
private var activeField : UIView?
var param:String!
var adminUser : Admin? = nil
var kbHeight: CGFloat!
override func viewDidLoad()
{
self.addKeyBoardObserver()
self.addGestureForHideKeyBoard()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func addGestureForHideKeyBoard()
{
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
}
func hideKeyboard() {
self.view.endEditing(true)
}
func addKeyBoardObserver(){
NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillHideNotification, object: nil)
}
func removeObserver(){
NSNotificationCenter.defaultCenter().removeObserver(self)
}
//MARK:- textfiled Delegate
func textFieldShouldBeginEditing(textField: UITextField) -> Bool
{
activeField = textField
return true
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool
{
if activeField == textField
{
activeField = nil
}
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if txtUserName == textField
{
txtUserPassword.becomeFirstResponder()
}
else if (textField == txtUserPassword)
{
self.btnAdminLoginAction(nil)
}
return true;
}
func willChangeKeyboardFrame(aNotification : NSNotification)
{
if self.activeField != nil && self.activeField!.isFirstResponder()
{
if let keyboardSize = (aNotification.userInfo![UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
{
let dy = (self.activeField?.superview?.convertRect((self.activeField?.frame)!, toView: view).origin.y)!
let height = (self.view.frame.size.height - keyboardSize.size.height)
if dy > height
{
var frame = self.view.frame
frame.origin.y = -((dy - height) + (self.activeField?.frame.size.height)! + 20)
self.view.frame = frame
}
}
}
else
{
var frame = self.view.frame
frame.origin.y = 0
self.view.frame = frame
}
} }
我正在使用swift 4,我解决了这个问题,没有使用任何额外的底部约束,看我的代码在这里。这对我的案子很有帮助
1)在did load中添加通知观察者
override func viewDidLoad() {
super.viewDidLoad ()
setupManager ()
//加载视图后进行任何额外的设置。
addobserver (self, selector: #selector(self. keyboardwillshow), name: NSNotification.Name。对象:nil)
addobserver (self, selector: #selector(self. keyboardwillhide), name: NSNotification.Name。对象:nil)
}
2)删除通知观察者
Deinit {
NotificationCenter.default.removeObserver(self)
}
3)增加键盘显示/隐藏方法
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y -= keyboardSize.height
self.view.layoutIfNeeded()
})
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y += keyboardSize.height
self.view.layoutIfNeeded()
})
}
}
4)添加textfield delegate和touchesBegan方法。usefull用于在屏幕上的textfield外触摸时隐藏键盘
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
我喜欢简洁的Swift代码。这是我能想出的最严格的代码,可以用键盘上下移动文本视图。它目前正在iOS8/9 Swift 2生产应用程序中运行。
更新(2016年3月):
我只是尽可能地压缩了之前的代码。此外,这里还有一些流行的答案,它们硬编码了键盘高度和动画参数。这是没有必要的,更不用说这些答案中的数字并不总是与我在6s+ iOS9上看到的实际值一致(键盘高度226,持续时间0.25,动画曲线7)。在任何情况下,几乎不需要额外的代码来直接从系统获取这些值。见下文。
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}
func animateWithKeyboard(notification: NSNotification) {
// Based on both Apple's docs and personal experience,
// I assume userInfo and its documented keys are available.
// If you'd like, you can remove the forced unwrapping and add your own default values.
let userInfo = notification.userInfo!
let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let moveUp = (notification.name == UIKeyboardWillShowNotification)
// baseContraint is your Auto Layout constraint that pins the
// text view to the bottom of the superview.
baseConstraint.constant = moveUp ? -keyboardHeight : 0
let options = UIViewAnimationOptions(rawValue: curve << 16)
UIView.animateWithDuration(duration, delay: 0, options: options,
animations: {
self.view.layoutIfNeeded()
},
completion: nil
)
}
注意:这段代码涵盖了大多数注释/一般情况。然而,处理不同的方向和/或自定义键盘可能需要更多的代码。如果你需要处理每一个场景,这可能会有所帮助。
我创建了一个Swift 3协议来处理键盘的出现/消失
import UIKit
protocol KeyboardHandler: class {
var bottomConstraint: NSLayoutConstraint! { get set }
func keyboardWillShow(_ notification: Notification)
func keyboardWillHide(_ notification: Notification)
func startObservingKeyboardChanges()
func stopObservingKeyboardChanges()
}
extension KeyboardHandler where Self: UIViewController {
func startObservingKeyboardChanges() {
// NotificationCenter observers
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
// Deal with rotations
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
// Deal with keyboard change (emoji, numerical, etc.)
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextInputCurrentInputModeDidChange, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillHide(notification)
}
}
func keyboardWillShow(_ notification: Notification) {
let verticalPadding: CGFloat = 20 // Padding between the bottom of the view and the top of the keyboard
guard let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardHeight = value.cgRectValue.height
// Here you could have more complex rules, like checking if the textField currently selected is actually covered by the keyboard, but that's out of this scope.
self.bottomConstraint.constant = keyboardHeight + verticalPadding
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
func keyboardWillHide(_ notification: Notification) {
self.bottomConstraint.constant = 0
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.layoutIfNeeded()
})
}
func stopObservingKeyboardChanges() {
NotificationCenter.default.removeObserver(self)
}
}
然后,要在UIViewController中实现它,执行以下操作:
let the viewController conform to this protocol :
class FormMailVC: UIViewControlle, KeyboardHandler {
start observing keyboard changes in viewWillAppear:
// MARK: - View controller life cycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startObservingKeyboardChanges()
}
stop observing keyboard changes in viewWillDisappear:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
stopObservingKeyboardChanges()
}
create an IBOutlet for the bottom constraint from the storyboard:
// NSLayoutConstraints
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
(I recommend having all of your UI embedded inside a "contentView", and linking to this property the bottom constraint from this contentView to the bottom layout guide)
change the constraint priority of the top constraint to 250 (low)
这是为了让整个内容视图在键盘出现时向上滑动。
优先级必须低于子视图中的任何其他约束优先级,包括内容拥抱优先级/内容抗压缩优先级。
确保你的自动布局有足够的约束来决定contentView应该如何滑动。
你可能需要添加一个“大于等于”的约束:
给你!
对于任何不使用故事板设置布局约束的人。这是一种纯粹的编程方式,让它在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)
}
}