ios - caracteristicas - Desplace UITextField sobre el teclado en un UITableViewCell en un UIViewController regular
ios 5 logo (10)
En swift4 podemos crear una extensión de UIViewController .
extension UIViewController {
//MARK: Keyboard user interactions
func handleContainerViewFrameOnKeyboardShowHide(originalContainerFrame: CGRect) {
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: OperationQueue.main) {(notification) in
var info = (notification as NSNotification).userInfo!
let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
var tableViewFrame = originalContainerFrame
tableViewFrame.size.height = originalContainerFrame.size.height - keyboardFrame.size.height
self.view.frame = tableViewFrame
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: OperationQueue.main) { (notification) in
self.view.frame = originalContainerFrame
}
}
}
He intentado la mayoría de los ejemplos aquí en StackOverflow. También utilicé Apple. El problema que parece que tengo con ellos es que no tienen en cuenta que UITextField está en un UITableView. He hecho esto muchas veces, pero no de esta manera. Tengo un UITableViewCell personalizado con un UITextField en él.
En mi UITableView (que NO es un UITableViewController), necesito poder evitar ocultar el UITextField bajo la UITableView.
Tengo esto a partir de ahora:
-(void)viewDidLoad
{
....
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
....
}
- (void)scrollToRectOfTextField {
UITableViewCell *cell = (UITableViewCell*)[self.activeTextField superview];
CGRect r = CGRectMake(self.activeTextField.frame.origin.x,
cell.frame.origin.y+self.activeTextField.frame.origin.y,
self.activeTextField.frame.size.width,
self.activeTextField.frame.size.height);
[self.tableView scrollRectToVisible:r animated:YES];
}
- (void)keyboardDidShow:(NSNotification *)notification
{
if (UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPhone) {
NSDictionary *userInfo = [notification userInfo];
CGSize size = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSLog(@"TableView: %@", NSStringFromCGRect(self.tableView.frame));
CGRect newTableViewFrame = CGRectMake(self.tableView.frame.origin.x,
self.tableView.frame.origin.y,
self.tableView.frame.size.width, self.tableView.frame.size.height - size.height);
self.tableView.frame = newTableViewFrame;
NSLog(@"New TableView: %@", NSStringFromCGRect(self.tableView.frame));
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height-size.height);
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
CGSize size = [[userInfo objectForKey: UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
self.tableView.frame = CGRectMake(self.tableView.frame.origin.x,
self.tableView.frame.origin.y,
self.tableView.frame.size.width,
self.tableView.frame.size.height + size.height);
NSLog(@"%@", NSStringFromCGRect(self.tableView.frame));
}
-(void)textFieldDidBeginEditing
{
[self scrollToRectOfTextField];
}
Esto parece empujar un montón de espacio en blanco más allá de mi teclado. Tenga en cuenta que también tengo un inputAccessoryView en mi UITextField también.
Ah, y no puedo usar ninguna clase de terceros. Me encanta TPKeyboardAvoidingScrollView, pero no puedo usar nada de terceros.
Esta respuesta es para usuarios de Xamarin iOS, sin embargo, alguien puede modificarla fácilmente para que funcione con Swift o Objective C.
La solución es muy simple y ha funcionado perfectamente en mi caso, donde necesitaba que apareciera una celda en la mitad superior de la pantalla para que el campo de texto de la celda estuviera por encima del teclado. Así que lo que hice es lo siguiente:
Implementé textField.ShouldBeginEditing de la siguiente manera:
myTextField.ShouldBeginEditing = textField =>
{
myTableView.ScrollToRow(indexPath, UITableViewScrollPosition.Top, true);
return true;
};
Dónde:
myTextField es el campo de texto de la celda,
myTableView es la vista de tabla,
indexPath es la ruta del índice de la celda dentro de la vista de tabla.
Como mencioné anteriormente, esta solución funciona perfectamente en mi caso, así que pensé que podría compartirla con ustedes en caso de que también les funcione. Feliz codificacion :)
Gracias a @Salman por el enlace.
Simplemente observe que el ejemplo de Apple se utiliza para scrollview en la vista normal.
En la vista de tabla, debe convertir Point y Rect de activeField en la coordenada de la tabla, así que cambio algunas líneas en la función keyboardWasShown:
func keyboardWasShown(aNotification: NSNotification) {
let info = aNotification.userInfo as! [String: AnyObject],
kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue().size,
contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)
self.tableBasket.contentInset = contentInsets
self.tableBasket.scrollIndicatorInsets = contentInsets
var aRect = self.view.frame
aRect.size.height -= kbSize.height
let pointInTable = activeField!.superview!.convertPoint(activeField!.frame.origin, toView: tableView)
let rectInTable = activeField!.superview!.convertRect(activeField!.frame, toView: tableView)
if !CGRectContainsPoint(aRect, pointInTable) {
self.tableView.scrollRectToVisible(rectInTable, animated: true)
}
}
Y si su vista tiene tabBarController, recuerde restablecer contentInsets con tabBar height en lugar de UIEdgeInsetsZero (de lo contrario, sus últimas filas inferiores pueden estar ocultas bajo tabBar):
func keyboardWillBeHidden(aNotification: NSNotification) {
//UIEdgeInsetsZero is used in view without tabBar
//let contentInsets = UIEdgeInsetsZero
let tabBarHeight = self.tabBarController!.tabBar.frame.height
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: tabBarHeight, right: 0)
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
}
}
Hice una mezcla con las respuestas de Matt y también de Salman . Esto funciona para muchos campos de texto en un tableView. Swift 3
Básicamente es obtener el punto BOTTOM Y del textInput tocado. Una vez que tengamos eso, verifico si el teclado cubre el textInput y si lo hago cambiaría el contentOffset de la tableView
Primer registro a las notificaciones. En el init, si es un UIView o en viewDidLoad si es un UIViewController:
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)
A continuación, configure el campo de texto tocado como entrada actual
var inputActive: UITextField!
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
inputActive = textInput
return true
}
Finalmente implementar el método de notificaciones:
func keyboardWillShow(notification: NSNotification) {
var userInfo = notification.userInfo!
if let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
// Get my height size
let myheight = tableView.frame.height
// Get the top Y point where the keyboard will finish on the view
let keyboardEndPoint = myheight - keyboardFrame.height
// Get the the bottom Y point of the textInput and transform it to the currentView coordinates.
if let pointInTable = inputActive.superview?.convert(inputActive.frame.origin, to: tableView) {
let textFieldBottomPoint = pointInTable.y + inputActive.frame.size.height + 20
// Finally check if the keyboard will cover the textInput
if keyboardEndPoint <= textFieldBottomPoint {
tableView.contentOffset.y = textFieldBottomPoint - keyboardEndPoint
} else {
tableView.contentOffset.y = 0
}
}
}
}
func keyboardWillHide(notification: NSNotification) {
tableView.contentOffset.y = 0
}
Pocas cosas para agregar. El relleno es una distancia extra que añado en mi caso fue de 20 puntos. También en mi caso, el UITableView se agregó a un UIViewController pero esto debería funcionar también en un UITableViewController
¡Espero que esto ayude!
Hice una mezcla entre la respuesta de @Victor y algunos códigos que tenía. Creé una extensión práctica que se puede usar en muchos UITextField.
1.- Primero necesitamos una extensión para que UITextField administre las notificaciones del teclado.
extension UITextField {
func keepTextFieldAboveKeyboard(tableView:UITableView) {
var willShowNotification: NSObjectProtocol?
var willHideNotification: NSObjectProtocol?
willShowNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: OperationQueue.main) {(notification) in
var userInfo = notification.userInfo!
if let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
// Get my height size
let myheight = tableView.frame.height
// Get the top Y point where the keyboard will finish on the view
let keyboardEndPoint = myheight - keyboardFrame.height
// Get the the bottom Y point of the textInput and transform it to the currentView coordinates.
if let pointInTable = self.superview?.convert(self.frame.origin, to: tableView) {
let textFieldBottomPoint = pointInTable.y + self.frame.size.height + 20
// Finally check if the keyboard will cover the textInput
if keyboardEndPoint <= textFieldBottomPoint {
tableView.contentOffset.y = textFieldBottomPoint - keyboardEndPoint
} else {
tableView.contentOffset.y = 0
}
}
}
NotificationCenter.default.removeObserver(willShowNotification!)
}
willHideNotification = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: OperationQueue.main) { (notification) in
tableView.contentOffset.y = 0
NotificationCenter.default.removeObserver(willHideNotification!)
}
}
}
2.- Esta extensión anterior debe llamarse dentro de textFieldShouldBeginEditing para que podamos tener una extensión para eso también.
extension UITextField : UITextFieldDelegate {
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
guard let tableView = textField.parentView(of: UITableView.self) else { return true };
textField.keepTextFieldAboveKeyboard(tableView:tableView);
return true;
}
}
3.- Finalmente, como se observa en el método anterior, necesitamos el TableView donde se encuentra la celda con el UITextField. Entonces podemos usar esta extensión (que también es útil para otros propósitos)
extension UIView {
func parentView<T: UIView>(of type: T.Type) -> T? {
guard let view = self.superview else {
return nil
}
return (view as? T) ?? view.parentView(of: T.self)
}
}
4.- Finalmente, en la celda donde se encuentra el UITextField , simplemente escribimos esta simple línea de código
textField.delegate = textField;
Completamente reutilizable y universal.
Mi solución (funcionó en Xcode 8.3.3, Swift 3, iOS 10.3.1):
class MyTableViewController: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(actionKeyboardDidShow(with:)), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(actionKeyboardWillHide(with:)), name: .UIKeyboardWillHide, object: nil)
}
override func viewDidDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
@objc private func actionKeyboardDidShow(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom += keyboardFrame.height
self.tableView.contentInset = contentInset
self.tableView.scrollIndicatorInsets = contentInset
}
@objc private func actionKeyboardWillHide(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom -= keyboardFrame.height
self.tableView.contentInset = contentInset
self.tableView.scrollIndicatorInsets = contentInset
}
}
Pasé todo el día tratando de resolver esto. Lo publiqué aquí, luego encontré un enlace de blog y una solución increíblemente simple. Se parece a esto:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGPoint pointInTable = [textField.superview convertPoint:textField.frame.origin toView:self.tableView];
CGPoint contentOffset = self.tableView.contentOffset;
contentOffset.y = (pointInTable.y - textField.inputAccessoryView.frame.size.height);
NSLog(@"contentOffset is: %@", NSStringFromCGPoint(contentOffset));
[self.tableView setContentOffset:contentOffset animated:YES];
return YES;
}
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
if ([textField.superview.superview isKindOfClass:[UITableViewCell class]])
{
UITableViewCell *cell = (UITableViewCell*)textField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:TRUE];
}
return YES;
}
Probé el enlace que @inturbidus publicó para iOS8 pero desafortunadamente no funcionó para mí. Después de un poco de investigación, resulta que Apple tiene un código de muestra en su sitio web para que esto funcione de manera natural como lo hacen en el UITableViewController. Aquí está el enlace de Apple para la versión de Objective-C y también estoy agregando la versión rápida aquí.
Enlace Objective-C de Apple (Desplácese hasta el listado 5-1): https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Rápida adaptación de la versión Objective-C.
var activeField: UITextField?
func textFieldDidBeginEditing(textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
self.activeField = nil
}
func registerForKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(aNotification: NSNotification) {
let info = aNotification.userInfo as! [String: AnyObject],
kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue().size,
contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it''s visible
// Your app might not need or want this behavior.
var aRect = self.view.frame
aRect.size.height -= kbSize.height
if !CGRectContainsPoint(aRect, activeField!.frame.origin) {
self.tableView.scrollRectToVisible(activeField!.frame, animated: true)
}
}
func keyboardWillBeHidden(aNotification: NSNotification) {
let contentInsets = UIEdgeInsetsZero
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
}
de actualizada a 4.2. Funciona en iOS 12.0.
Swift 4.2
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(with:)), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(with:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardDidShow(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom += keyboardFrame.height
tableView.contentInset = contentInset
tableView.scrollIndicatorInsets = contentInset
}
@objc func keyboardWillHide(with notification: Notification) {
guard let userInfo = notification.userInfo as? [String: AnyObject],
let keyboardFrame = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
else { return }
var contentInset = self.tableView.contentInset
contentInset.bottom -= keyboardFrame.height
tableView.contentInset = contentInset
tableView.scrollIndicatorInsets = contentInset
}
Desplace UITextField sobre el teclado en un UITableViewCell en un UIViewController swift 3 y Xcode 8.1
1) establecer Delegado = UITextFieldDelegate
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(DayViewController.keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
NotificationCenter.default.addObserver(self, selector: #selector(DayViewController.keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.activeField = nil
}
//MARK: - Keyboard Show and Hide Methods
func keyboardWillShow(notification: NSNotification)
{
let info = notification.userInfo! as! [String: AnyObject],
kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue.size,
contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)
self.FourthTblMainTableView.contentInset = contentInsets
self.FourthTblMainTableView.scrollIndicatorInsets = contentInsets
var aRect = self.FourthTblMainTableView.frame
aRect.size.height -= kbSize.height
}
func keyboardWillHide(notification: NSNotification)
{
let contentInsets = UIEdgeInsets.zero
self.FourthTblMainTableView.contentInset = contentInsets
self.FourthTblMainTableView.scrollIndicatorInsets = contentInsets
}