我有一个应用,它在视图的下半部分有一个文本框。 这意味着当我在文本框中输入时,键盘会覆盖文本框。
我如何在打字时向上移动视图,这样我就可以看到我键入的内容,然后在键盘消失时将它移回原来的位置?
我到处都看了,但所有的解似乎都在Obj-C中,我还不能完全转换。
任何帮助都将不胜感激。
我有一个应用,它在视图的下半部分有一个文本框。 这意味着当我在文本框中输入时,键盘会覆盖文本框。
我如何在打字时向上移动视图,这样我就可以看到我键入的内容,然后在键盘消失时将它移回原来的位置?
我到处都看了,但所有的解似乎都在Obj-C中,我还不能完全转换。
任何帮助都将不胜感激。
当前回答
移动视图的原点是一种幼稚的方法。
这里有一个更好的解决方案:当键盘出现时调整视图的高度。
let viewHeight = self.view.frame.height
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.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.height == self.viewHeight{
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - keyboardSize.height)
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height + keyboardSize.height)
}
}
其他回答
由于在Combine中没有如何做到这一点的答案,这里是我使用的方法。
我们创建一个发布者来监听通知,显示和隐藏。 为了显示,我们从通知userInfo中获取键盘帧,并检查当前活动响应器是否包含在其中。如果被覆盖,返回键盘帧高度。如果它没有被覆盖,返回0,我们不想移动帧。对于隐藏通知,我们简单地返回0。
private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect }
.map { $0.intersects(self.view.firstResponder!.frame) ? $0.height : 0 }
.map { $0 * -1 },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
).eraseToAnyPublisher()
}
在viewDidLoad中,我们只需订阅发布者,相应地改变视图框架。
override func viewDidLoad() {
super.viewDidLoad()
keyboardHeightPublisher.sink{ [weak self] height in
self?.view.frame.origin.y = height
}.store(in: &cancelables)
}
编辑 小心!如果firstResponder在子视图中,你必须计算与整个屏幕相对应的帧,以检查它们是否相交。 例子:
let myViewGlobalFrame = myView.convert(myView.frame, to: parentView)
这个视频教程是最好的。7分钟长,会很有意义。这样一个简单的解决方案,当你有多个文本字段,并希望滚动视图移动“x”数量的像素时,特定的文本字段被点击。
https://youtu.be/VuiPGJOEBH4
就这些步骤:
-把你所有的文本字段放在一个滚动视图中,约束到视图的边缘。
-连接所有的文本字段和滚动视图作为视图控制器的委托。
-用IBOutlet连接所有文本字段和滚动视图。
class ViewController: UIViewController, UITextFieldDelegate {
添加UITextFieldDelegate协议到你的类中
@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!
@IBOutlet weak var scrollView: UIScrollView!
-在swift文件中添加UITextFieldDelegate方法:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
if (textField == self.stateAddress) {
scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
}
else if (textField == self.zipAddress) {
scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
}
else if (textField == self.phoneNumber) {
scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
}
else if (textField == self.vetEmailAddress) {
scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
}
}
func textFieldDidEndEditing(textField: UITextField) {
scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}
第一种方法只是激活键盘上的返回按钮来关闭键盘。第二个是当你点击到任何特定的文本域,然后设置你的滚动视图滚动的距离的y偏移(我的是基于我的视图控制器上的y位置25,57,112,142)。最后一个说,当你从键盘上点击时,滚动视图会回到原来的位置。
我使我的视图像素完美的这种方式!
对于黑屏错误(Swift 4和4.2)。
我解决了黑屏的问题。在验证方案中,敲击后键盘高度变化,导致黑屏。
必须使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey
var isKeyboardAppear = false
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if !isKeyboardAppear {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
isKeyboardAppear = true
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if isKeyboardAppear {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
isKeyboardAppear = false
}
}
移动视图的原点是一种幼稚的方法。
这里有一个更好的解决方案:当键盘出现时调整视图的高度。
let viewHeight = self.view.frame.height
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.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.height == self.viewHeight{
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height - keyboardSize.height)
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height + keyboardSize.height)
}
}
Swift 4中的Simpelst方法
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var myTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
myTextField.resignFirstResponder()
}
func keyboardWillShow(notification: NSNotification) {
// let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]
// print("duration",duration)
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight : Int = Int(keyboardSize.height)
print("keyboardWillShow",keyboardHeight)
if let height = UserDefaults.standard.value(forKey: "keyboardHeight") as? (Int) {
moveTextField(myTextField, moveDistance: -height as Int, moveDuration: 0.43, up: true)
}else{
UserDefaults.standard.set(keyboardHeight, forKey: "keyboardHeight")
moveTextField(myTextField, moveDistance: -keyboardHeight, moveDuration: 0.43, up: true)
}
}
}
func keyboardWillHide(notification: NSNotification){
if let height = UserDefaults.standard.value(forKey: "keyboardHeight") as? (Int) {
moveTextField(myTextField, moveDistance: -height as Int, moveDuration: 0.25, up: false)
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func moveTextField(_ textField: UITextField, moveDistance: Int, moveDuration: Double, up: Bool) {
let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(moveDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
}
你也可以上下移动只有UITextFiled而不是整个屏幕(UIView)。 用这种方法。
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
And
@objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.textField.frame.origin.y+=deltaY
},completion: nil)
}