J'ai essayé la plupart des exemples ici sur StackOverflow. J'ai aussi utilisé Apple. Le problème que je semble avoir avec eux est qu’ils ne tiennent pas compte de la présence de UITextField dans une UITableView. Je l'ai fait plusieurs fois, mais pas de cette façon. J'ai un UITableViewCell personnalisé avec un UITextField.
Sur mon UITableView (qui n'est pas un UITableViewController), je dois pouvoir éviter de masquer UITextField sous UITableView.
J'ai ceci à partir de maintenant:
-(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];
}
Cela semble pousser un tas d'espaces blancs au-delà de mon clavier. Veuillez également noter que j'ai également un inputAccessoryView sur mon UITextField.
Oh, et je ne peux utiliser aucune classe tierce. J'adore TPKeyboardAvoidingScrollView, mais je ne peux rien utiliser de tiers.
J'ai passé toute la journée à essayer de comprendre cela. Je l'ai posté ici, puis j'ai trouvé un lien vers un blog et une solution incroyablement simple. Cela ressemble à ceci:
-(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;
}
J'ai essayé le lien que @inturbidus a publié pour iOS8, mais malheureusement, cela n'a pas fonctionné pour moi. Après quelques recherches, il s'avère qu'Apple a un exemple de code sur son site Web pour que cela fonctionne naturellement comme dans UITableViewController. Voici le lien Apple pour la version Objective-C et j'ajoute également la version Swift ici.
Lien Objective-C d’Apple (Sélectionnez le nom 5-1):https://developer.Apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Adaptation rapide de la version 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
}
Merci @Salman pour le lien.
Il suffit de remarquer que l’exemple Apple est utilisé pour le défilement dans une vue normale.
En mode tableau, vous devez convertir les points et rect de activeField en coordonnées de tableau, je modifie donc certaines lignes de la fonction 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)
}
}
Et si votre vue contient tabBarController, n'oubliez pas de réinitialiser contentInsets avec tabBar height à la place de UIEdgeInsetsZero (sinon, vos dernières lignes inférieures peuvent être masquées sous 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
}
}
J'ai fait un mélange avec les réponses de Matt et aussi Salman . Cela fonctionne pour de nombreux champs de texte dans un tableau. Swift 3
Fondamentalement est d'obtenir le BOTTOM Y point du textInput touché. Une fois que nous avons ce que je vérifie si le clavier couvre le textInput et si je le fais je changerais le contentOffset de la tableView
Commencez par vous inscrire aux notifications. Dans init si est un UIView ou dans viewDidLoad si est 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)
Puis configurez le champ de texte touché comme entrée courante
var inputActive: UITextField!
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
inputActive = textInput
return true
}
Enfin, implémentez la méthode de notification:
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
}
Peu de choses à ajouter. Le padding est une distance supplémentaire que j’ajoute dans mon cas était de 20 points .
J'espère que cela t'aides!
Ma solution (travaillé sur 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
}
}
J'ai fait un mélange entre la réponse de @Victor et du code que j'avais… .. J'ai créé une extension pratique pouvant être utilisée sur de nombreux UITextField.
1.- Nous avons d’abord besoin d’une extension pour UITextField pour gérer les notifications au clavier
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.- Cette extension précédente doit être appelée dans textFieldShouldBeginEditing afin que nous puissions avoir une extension pour cela aussi
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.- Enfin, comme vous le remarquerez dans la méthode précédente, nous avons besoin de TableView où se trouve la cellule avec UITextField. Nous pouvons donc utiliser cette extension (qui est également utile à d'autres fins)
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.- Enfin dans la cellule où se trouve UITextField , nous écrivons simplement cette simple ligne de code
textField.delegate = textField;
Complètement réutilisable et universel.
Cette réponse s’adresse aux utilisateurs de Xamarin iOS, mais il est facile de la modifier pour la faire fonctionner avec Swift ou Objective C.
La solution est très simple et a parfaitement fonctionné dans mon cas où il me fallait une cellule pour apparaître dans la moitié supérieure de l'écran afin que le champ de texte de la cellule soit au-dessus du clavier. Donc ce que j'ai fait est le suivant:
J'ai implémenté textField.ShouldBeginEditing de la manière suivante:
myTextField.ShouldBeginEditing = textField =>
{
myTableView.ScrollToRow(indexPath, UITableViewScrollPosition.Top, true);
return true;
};
Où:
myTextFieldest le champ de texte de la cellule,
myTableViewest la vue tabulaire,
indexPathest le chemin d'index de la cellule dans la vue Table.
Comme je l'ai déjà mentionné, cette solution fonctionne parfaitement dans mon cas, alors j'ai pensé que je pourrais la partager avec vous au cas où cela fonctionnerait pour vous également. Bonne codage :)
La solution de jqgsninimo a été mise à jour à la version 4.2. Fonctionne sur 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
}
Faites défiler UITextField au-dessus du clavier dans une UITableViewCell sur un UIViewController standard Swift 3 et Xcode 8.1
1) définir Delegate = 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
}
Dans Swift4, nous pouvons créer une extension 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
}
}
}