Swift 通过 UiscrollView 滚动到 UITextField 仅在第一次出现错误
Swift Scroll to UITextField via UiscrollView only acts first time bug
我在这里发布我的完整代码。问题出在最初加载应用程序和 viewcontroller 时。它完全有效。点击两个文本字段,滚动视图向上推,键盘位于当前文本字段下方。但是如果点击文本字段.. 向上移动视图并在文本字段上重新点击它就不再这样做了。此外,如果通过导航控制器返回然后再次加载此 viewcontroller,它不会执行任何操作。它不再滚动了..(不再将文本字段向上推并且键盘不再位于其下方)...
import UIKit
import Parse
import Alamofire
import SwiftyJSON
class VCreservacion: UIViewController,UITextFieldDelegate,UIScrollViewDelegate {
var SUCURSALID = 0
var EMP_NOMBRE = ""
var DIRECCION = ""
var PROVINCIA = ""
var RESTID = 20556
@IBOutlet var lbl_empresa: UILabel!
@IBOutlet var lbl_direccion: UILabel!
@IBOutlet var lbl_step: UILabel!
@IBOutlet var cantidadView: UIView!
@IBOutlet var datePicker: UIDatePicker!
@IBOutlet var btn_reservar: UIButton!
@IBOutlet var stackView: UIStackView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var txtComentario: UITextField!
@IBOutlet weak var txtCelular: UITextField!
var activeField: UITextField?
var steps = 2
// MARK: RESERVE ACTION
@IBAction func ReserveAction(_ sender: UIButton) {
print("Reservando...")
// For date formater
var dateformated = ""
var dateformated2 = ""
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
//formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) as TimeZone!
dateformated = formatter.string(from: datePicker.clampedDate)
dateformated2 = formatter.string(from: datePicker.date)
print(dateformated)
print(dateformated2)
let cart = Cart.sharedInstance
guard let user = PFUser.current() else {
cart.showAlertView("Login", message: "Debes estar logeado para poder reservar.")
return
}
Alamofire.request("URL String", parameters: ["qty": "\(steps)","sucursalid":"\(self.SUCURSALID)","restid":"\(RESTID)","comment":"\(txtComentario.text!)","phone":"\(txtCelular.text!)","datetime":"\(dateformated)","action":"request","userid":"\(user.objectId!)"]).authenticate(usingCredential: cart.credential).responseJSON() {
response in
if (response.error != nil ) {
print(response.error.debugDescription)
print(response.request)
cart.showAlertView("Error", message: "there was an error.")
}
if(response.result.value != nil) {
let json = JSON(response.result.value!);
print(json);
let success:Bool = json["success"].boolValue
let error: Bool = json["error"].boolValue
if(success) {
print("con exito")
let alert = UIAlertController(title: "Reserva Enviada", message: "Tu reserva ha sido enviada y será revisada por el establecimiento", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
// Get the previous Controller.
let targetController: UIViewController = (self.navigationController?.viewControllers[self.navigationController!.viewControllers.count - 3])!
// And go to that Controller
self.navigationController?.popToViewController(targetController, animated: true)
}
alert.addAction(okAction)
self.present(alert,animated:true)
}
}
}
}
@IBAction func stepperValue(_ sender: UIStepper) {
self.lbl_step.text = Int(sender.value).description
steps = Int(sender.value)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
registerForKeyboardNotifications()
self.scrollView.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deregisterFromKeyboardNotifications()
self.scrollView.delegate = nil
}
// MARK: Viewdidload
override func viewDidLoad() {
super.viewDidLoad()
// enable scroll on scrollview
self.scrollView.isScrollEnabled = true
// step label initial value 2
self.lbl_step.text = "2"
// Get celular or phone
if ( Cart.sharedInstance.User_celular != "") {
txtCelular.text = Cart.sharedInstance.User_celular
} else {
txtCelular.text = Cart.sharedInstance.User_phone
}
let nearesthour = Date().nearestHour()
self.datePicker.minimumDate = nearesthour
self.txtComentario.delegate = self
self.txtCelular.delegate = self
self.txtCelular.tag = 20
self.scrollView.delegate = self
// tap gesture recognizer
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
self.scrollView.addGestureRecognizer(tap)
print("el enarest hour es \(nearesthour as Date?) y el date normal es \(Date())")
self.btn_reservar.layer.cornerRadius = 10
self.cantidadView.layer.cornerRadius = 10
self.lbl_empresa.text = EMP_NOMBRE
self.lbl_direccion.text = DIRECCION
/*
print("VC Reservacion")
print("SUCURSAL \(SUCURSALID) ")
print("EMP NOMBRE " + EMP_NOMBRE)
print("DIRECCION " + DIRECCION)
*/
}
// MARK: TEXTFIELD STUFF
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
self.activeField = textField
return true
}
/*
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
*/
func textFieldDidEndEditing(_ textField: UITextField) {
activeField = nil
}
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
print(" Keyboaard shown")
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
print(" el keyboardsize is \(keyboardSize)")
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height + 80, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
print("VIEW COMPLETE FRAME IS \(aRect)")
print("KEYBOARD FRAME HEIGHT \(keyboardSize!.height)")
aRect.size.height -= keyboardSize!.height
print("FRAME MENOS KEYBOARD ES \(aRect)")
print("SCROLLVIEW CONTENT \(self.scrollView.contentSize)")
if let activeField = self.activeField {
print("ACTIVEFIELD FRAME ORIGIN \(activeField.frame.origin) ")
print("Active field is textfield tag is \(activeField.tag)")
// if (!aRect.contains(activeField.frame.origin)){
print("arect Does Not contains activeField")
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
print("TEXTFIELD FRAME ES \(activeField.frame)")
print(" SCROLLVIEW CONTENT \(self.scrollView.contentSize)")
//}
}
}
@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.activeField = nil
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
}
@objc func handleTap(_ sender: UITapGestureRecognizer) {
self.view.endEditing(true)
print("Tap")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height)
print(" SCROLLVIEW CONTENT AFTER SUBVIEWS \(self.scrollView.contentSize)")
}
/* // NOT WORKING BECAUSE OF UISCROLLVIEW IN PLACE, MUST USE UITAPGESTURE RECOGNIZER
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
self.activeField?.resignFirstResponder()
}
*/
}
我遇到了同样的问题。显然,获取键盘的大小发生了变化。我将 UIKeyboardFrameBeginUserInfoKey 更改为 UIKeyboardFrameEndUserInfoKey 并让它再次工作。
这是我在按下文本字段时移动视图的确切代码
@objc func keyboardWasShown(notification: NSNotification){
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
guard let kbHeight = keyboardSize?.height else{return}
aRect.size.height -= kbHeight
if let activeField = self.activeTextField {
if (!aRect.contains(activeField.frame.origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}
我在这里发布我的完整代码。问题出在最初加载应用程序和 viewcontroller 时。它完全有效。点击两个文本字段,滚动视图向上推,键盘位于当前文本字段下方。但是如果点击文本字段.. 向上移动视图并在文本字段上重新点击它就不再这样做了。此外,如果通过导航控制器返回然后再次加载此 viewcontroller,它不会执行任何操作。它不再滚动了..(不再将文本字段向上推并且键盘不再位于其下方)...
import UIKit
import Parse
import Alamofire
import SwiftyJSON
class VCreservacion: UIViewController,UITextFieldDelegate,UIScrollViewDelegate {
var SUCURSALID = 0
var EMP_NOMBRE = ""
var DIRECCION = ""
var PROVINCIA = ""
var RESTID = 20556
@IBOutlet var lbl_empresa: UILabel!
@IBOutlet var lbl_direccion: UILabel!
@IBOutlet var lbl_step: UILabel!
@IBOutlet var cantidadView: UIView!
@IBOutlet var datePicker: UIDatePicker!
@IBOutlet var btn_reservar: UIButton!
@IBOutlet var stackView: UIStackView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var txtComentario: UITextField!
@IBOutlet weak var txtCelular: UITextField!
var activeField: UITextField?
var steps = 2
// MARK: RESERVE ACTION
@IBAction func ReserveAction(_ sender: UIButton) {
print("Reservando...")
// For date formater
var dateformated = ""
var dateformated2 = ""
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
//formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) as TimeZone!
dateformated = formatter.string(from: datePicker.clampedDate)
dateformated2 = formatter.string(from: datePicker.date)
print(dateformated)
print(dateformated2)
let cart = Cart.sharedInstance
guard let user = PFUser.current() else {
cart.showAlertView("Login", message: "Debes estar logeado para poder reservar.")
return
}
Alamofire.request("URL String", parameters: ["qty": "\(steps)","sucursalid":"\(self.SUCURSALID)","restid":"\(RESTID)","comment":"\(txtComentario.text!)","phone":"\(txtCelular.text!)","datetime":"\(dateformated)","action":"request","userid":"\(user.objectId!)"]).authenticate(usingCredential: cart.credential).responseJSON() {
response in
if (response.error != nil ) {
print(response.error.debugDescription)
print(response.request)
cart.showAlertView("Error", message: "there was an error.")
}
if(response.result.value != nil) {
let json = JSON(response.result.value!);
print(json);
let success:Bool = json["success"].boolValue
let error: Bool = json["error"].boolValue
if(success) {
print("con exito")
let alert = UIAlertController(title: "Reserva Enviada", message: "Tu reserva ha sido enviada y será revisada por el establecimiento", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
// Get the previous Controller.
let targetController: UIViewController = (self.navigationController?.viewControllers[self.navigationController!.viewControllers.count - 3])!
// And go to that Controller
self.navigationController?.popToViewController(targetController, animated: true)
}
alert.addAction(okAction)
self.present(alert,animated:true)
}
}
}
}
@IBAction func stepperValue(_ sender: UIStepper) {
self.lbl_step.text = Int(sender.value).description
steps = Int(sender.value)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
registerForKeyboardNotifications()
self.scrollView.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deregisterFromKeyboardNotifications()
self.scrollView.delegate = nil
}
// MARK: Viewdidload
override func viewDidLoad() {
super.viewDidLoad()
// enable scroll on scrollview
self.scrollView.isScrollEnabled = true
// step label initial value 2
self.lbl_step.text = "2"
// Get celular or phone
if ( Cart.sharedInstance.User_celular != "") {
txtCelular.text = Cart.sharedInstance.User_celular
} else {
txtCelular.text = Cart.sharedInstance.User_phone
}
let nearesthour = Date().nearestHour()
self.datePicker.minimumDate = nearesthour
self.txtComentario.delegate = self
self.txtCelular.delegate = self
self.txtCelular.tag = 20
self.scrollView.delegate = self
// tap gesture recognizer
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
self.scrollView.addGestureRecognizer(tap)
print("el enarest hour es \(nearesthour as Date?) y el date normal es \(Date())")
self.btn_reservar.layer.cornerRadius = 10
self.cantidadView.layer.cornerRadius = 10
self.lbl_empresa.text = EMP_NOMBRE
self.lbl_direccion.text = DIRECCION
/*
print("VC Reservacion")
print("SUCURSAL \(SUCURSALID) ")
print("EMP NOMBRE " + EMP_NOMBRE)
print("DIRECCION " + DIRECCION)
*/
}
// MARK: TEXTFIELD STUFF
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
self.activeField = textField
return true
}
/*
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
*/
func textFieldDidEndEditing(_ textField: UITextField) {
activeField = nil
}
func registerForKeyboardNotifications(){
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications(){
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWasShown(notification: NSNotification){
//Need to calculate keyboard exact size due to Apple suggestions
print(" Keyboaard shown")
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
print(" el keyboardsize is \(keyboardSize)")
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height + 80, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
print("VIEW COMPLETE FRAME IS \(aRect)")
print("KEYBOARD FRAME HEIGHT \(keyboardSize!.height)")
aRect.size.height -= keyboardSize!.height
print("FRAME MENOS KEYBOARD ES \(aRect)")
print("SCROLLVIEW CONTENT \(self.scrollView.contentSize)")
if let activeField = self.activeField {
print("ACTIVEFIELD FRAME ORIGIN \(activeField.frame.origin) ")
print("Active field is textfield tag is \(activeField.tag)")
// if (!aRect.contains(activeField.frame.origin)){
print("arect Does Not contains activeField")
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
print("TEXTFIELD FRAME ES \(activeField.frame)")
print(" SCROLLVIEW CONTENT \(self.scrollView.contentSize)")
//}
}
}
@objc func keyboardWillBeHidden(notification: NSNotification){
//Once keyboard disappears, restore original positions
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
self.activeField = nil
self.view.endEditing(true)
self.scrollView.isScrollEnabled = false
}
@objc func handleTap(_ sender: UITapGestureRecognizer) {
self.view.endEditing(true)
print("Tap")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height)
print(" SCROLLVIEW CONTENT AFTER SUBVIEWS \(self.scrollView.contentSize)")
}
/* // NOT WORKING BECAUSE OF UISCROLLVIEW IN PLACE, MUST USE UITAPGESTURE RECOGNIZER
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
self.activeField?.resignFirstResponder()
}
*/
}
我遇到了同样的问题。显然,获取键盘的大小发生了变化。我将 UIKeyboardFrameBeginUserInfoKey 更改为 UIKeyboardFrameEndUserInfoKey 并让它再次工作。
这是我在按下文本字段时移动视图的确切代码
@objc func keyboardWasShown(notification: NSNotification){
self.scrollView.isScrollEnabled = true
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size
let contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
self.scrollView.contentInset = contentInsets
self.scrollView.scrollIndicatorInsets = contentInsets
var aRect : CGRect = self.view.frame
guard let kbHeight = keyboardSize?.height else{return}
aRect.size.height -= kbHeight
if let activeField = self.activeTextField {
if (!aRect.contains(activeField.frame.origin)){
self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
}