Avec le SDK iOS:
J'ai une UIView
avec UITextField
s qui fait apparaître un clavier. J'en ai besoin pour pouvoir:
Autoriser le défilement du contenu de la UIScrollView
pour voir les autres champs de texte une fois le clavier affiché
"Sauter" automatiquement (en faisant défiler vers le haut) ou raccourcir
Je sais que j'ai besoin d'une UIScrollView
. J'ai essayé de changer la classe de ma UIView
en UIScrollView
mais je ne parviens toujours pas à faire défiler les zones de texte vers le haut ou le bas.
Ai-je besoin à la fois d'une UIView
et d'une UIScrollView
? Est-ce que l'un va dans l'autre?
Que faut-il implémenter pour faire défiler automatiquement jusqu'au champ de texte actif?
Dans l'idéal, autant de configurations de composants que possible seront effectuées dans Interface Builder. Je voudrais écrire uniquement du code pour ce qui en a besoin.
Remarque: la UIView
(ou UIScrollView
) avec laquelle je travaille est affichée par un onglet (UITabBar
), qui doit fonctionner normalement.
Edit: J'ajoute la barre de défilement uniquement lorsque le clavier apparaît. Même si ce n’est pas nécessaire, j’ai l’impression que cette interface offre une meilleure interface, car elle permet à l’utilisateur de faire défiler et de modifier les zones de texte, par exemple.
Je le fais fonctionner où je change la taille de la UIScrollView
quand le clavier monte et descend. J'utilise simplement:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
scrollView.frame = CGRectMake(scrollView.frame.Origin.x,
scrollView.frame.Origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50); //resize
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
//keyboard will hide
scrollView.frame = CGRectMake(scrollView.frame.Origin.x,
scrollView.frame.Origin.y,
scrollView.frame.size.width,
scrollView.frame.size.height + 215 - 50); //resize
}
Cependant, cela ne "remonte" pas automatiquement ni ne centre les champs de texte inférieurs dans la zone visible, ce que j'aimerais vraiment.
Vous aurez seulement besoin d'un ScrollView
si le contenu que vous avez maintenant ne correspond pas à l'écran de l'iPhone. (Si vous ajoutez le ScrollView
comme vue d'ensemble des composants. Juste pour que le TextField
défile vers le haut lorsque le clavier apparaît, alors ce n'est pas nécessaire.)
Pour afficher le textfields
sans être masqué par le clavier, la méthode standard consiste à déplacer la vue vers le haut/le bas avec des champs de texte chaque fois que le clavier est affiché.
Voici un exemple de code:
#define kOFFSET_FOR_KEYBOARD 80.0
-(void)keyboardWillShow {
// Animate the current view out of the way
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)keyboardWillHide {
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
else if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:mailTf])
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y >= 0)
{
[self setViewMovedUp:YES];
}
}
}
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's Origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.Origin.y -= kOFFSET_FOR_KEYBOARD;
rect.size.height += kOFFSET_FOR_KEYBOARD;
}
else
{
// revert back to the normal state.
rect.Origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
Je rencontrais également de nombreux problèmes avec une composition UIScrollView
composée de plusieurs UITextFields
, dont une ou plusieurs seraient masquées par le clavier lors de leur modification.
Voici quelques éléments à prendre en compte si votre UIScrollView
ne défile pas correctement.
1) Assurez-vous que votre contentSize est supérieur à la taille du cadre UIScrollView
. La façon de comprendre UIScrollViews
est que UIScrollView
est comme une fenêtre d'affichage sur le contenu défini dans le contentSize. Donc, pour que UIScrollview
puisse défiler n'importe où, contentSize doit être supérieur à UIScrollView
. Sinon, aucun défilement n'est requis car tout ce qui est défini dans contentSize est déjà visible. BTW, par défaut contentSize = CGSizeZero
.
2) Maintenant que vous comprenez que UIScrollView
est vraiment une fenêtre sur votre "contenu", le moyen de s’assurer que le clavier n’obscurcit pas votre "fenêtre" de UIScrollView's
consiste à redimensionner le UIScrollView
de sorte que lorsque le clavier est présent, avoir la fenêtre UIScrollView
dimensionnée uniquement à l'original UIScrollView
frame.size.height moins la hauteur du clavier. Cela garantira que votre fenêtre est seulement cette petite zone visible.
3) Voici le piège: Quand j'ai implémenté ceci pour la première fois, j'ai pensé que je devrais obtenir le CGRect
du champ de texte édité et appeler la méthode UIScrollView's
scrollRecToVisible. J'ai implémenté la méthode UITextFieldDelegate
textFieldDidBeginEditing
avec l'appel de la méthode scrollRecToVisible
. Cela fonctionnait réellement avec un effet secondaire étrange que le défilement serait enclenché le UITextField
en position. Pendant longtemps, je ne pouvais pas comprendre ce que c'était. Ensuite, j'ai commenté la méthode textFieldDidBeginEditing
Delegate et tout fonctionne !! (???). En fin de compte, je crois que UIScrollView
amène implicitement implicitement le UITextField
actuellement édité dans la fenêtre visualisable. Mon implémentation de la méthode UITextFieldDelegate
et l'appel suivant à scrollRecToVisible
étaient redondants et étaient à l'origine de cet effet secondaire étrange.
Voici donc les étapes à suivre pour faire défiler correctement votre UITextField
dans un UIScrollView
lorsque le clavier apparaît.
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.view.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.view.window];
keyboardIsShown = NO;
//make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
CGSize scrollContentSize = CGSizeMake(320, 345);
self.scrollView.contentSize = scrollContentSize;
}
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height += (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown. This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`. If we were to resize the `UIScrollView` again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.scrollView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.scrollView setFrame:viewFrame];
[UIView commitAnimations];
keyboardIsShown = YES;
}
viewDidLoad
viewDidUnload
contentSize
est défini et supérieur à UIScrollView
à viewDidLoad
.UIScrollView
quand le clavier est présentUIScrollView
lorsque le clavier s’éloigne.UITextField
est mis en onglet, même si le clavier est déjà présent pour éviter rétrécir le UIScrollView
quand il est déjà rétréci Une chose à noter est que le UIKeyboardWillShowNotification
se déclenche même lorsque le clavier est déjà à l'écran lorsque vous utilisez un autre UITextField
. Je me suis occupé de cela en utilisant un ivar pour éviter de redimensionner le UIScrollView
quand le clavier est déjà à l'écran. Redimensionner par inadvertance le UIScrollView
quand le clavier est déjà là serait désastreux!
J'espère que ce code évite à certains d'entre vous beaucoup de maux de tête.
En fait, il est préférable d'utiliser l'implémentation d'Apple, comme indiqué dans docs . Cependant, le code qu'ils fournissent est défectueux. Remplacez la partie trouvée dans keyboardWasShown:
juste en dessous des commentaires comme suit:
NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);
CGPoint Origin = activeRect.Origin;
Origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, Origin)) {
CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
[backScrollView setContentOffset:scrollPoint animated:YES];
}
Les problèmes avec le code Apple sont les suivants: (1) Ils calculent toujours si le point est dans le cadre de la vue, mais il s'agit d'une ScrollView
, de sorte qu'il a peut-être déjà défilé et que vous devez tenir compte de ce décalage:
Origin.y -= scrollView.contentOffset.y
(2) Ils décalent le contentOffset de la hauteur du clavier, mais nous voulons l’inverse (nous voulons décaler la contentOffset
de la hauteur visible à l’écran, pas de ce qui ne l’est pas):
activeField.frame.Origin.y-(aRect.size.height)
Dans textFieldDidBeginEditting
et dans textFieldDidEndEditing
, appelez la fonction [self animateTextField:textField up:YES]
comme suit:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -130; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: @"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
J'espère que ce code vous aidera.
Dans Swift 2
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField, up:false)
}
Swift 3
func animateTextField(textField: UITextField, up: Bool)
{
let movementDistance:CGFloat = -130
let movementDuration: Double = 0.3
var movement:CGFloat = 0
if up
{
movement = movementDistance
}
else
{
movement = -movementDistance
}
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
func textFieldDidBeginEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:true)
}
func textFieldDidEndEditing(textField: UITextField)
{
self.animateTextField(textField: textField, up:false)
}
Juste en utilisant TextFields:
1a) Utilisation de Interface Builder
: Sélectionnez All TextFields => Edit => Embed In => ScrollView
1b) Intégrez manuellement les TextField dans UIScrollView appelé scrollView
2) Définir UITextFieldDelegate
3) Définissez chaque textField.delegate = self;
(ou établissez des connexions dans Interface Builder
)
4) Copier/coller:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
CGPoint scrollPoint = CGPointMake(0, textField.frame.Origin.y);
[scrollView setContentOffset:scrollPoint animated:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[scrollView setContentOffset:CGPointZero animated:YES];
}
Pour Universal Solution, voici mon approche pour implémenter IQKeyboardManager .
Step1: - J'ai ajouté les notifications globales de UITextField
, UITextView
et UIKeyboard
dans une classe singleton. Je l’appelle IQKeyboardManager .
Step2: - Si on trouve des notifications UIKeyboardWillShowNotification
, UITextFieldTextDidBeginEditingNotification
ou UITextViewTextDidBeginEditingNotification
, j'essaie d'obtenir l'instance topMostViewController
à partir de la hiérarchie UIWindow.rootViewController
. Afin de découvrir correctement la variable UITextField
UITextView
, le cadre de topMostViewController.view
doit être ajusté.
_/Étape 3: - J'ai calculé la distance de déplacement attendue de topMostViewController.view
par rapport à la première réponse UITextField
UITextView
.
_/Step4: - J'ai déplacé topMostViewController.view.frame
haut/bas en fonction de la distance de déplacement attendue.
Step5: - Si on trouve la notification UIKeyboardWillHideNotification
, UITextFieldTextDidEndEditingNotification
ou UITextViewTextDidEndEditingNotification
, j'essaie à nouveau d'obtenir l'instance topMostViewController
de la hiérarchie UIWindow.rootViewController
.
Step6: - J'ai calculé la distance perturbée de topMostViewController.view
qui doit être restaurée à sa position d'origine.
Step7: - J'ai restauré topMostViewController.view.frame
en fonction de la distance perturbée.
Step8: - J'ai instancié singleton IQKeyboardManager instance de classe lors du chargement de l'application, ainsi chaque UITextField
UITextView
dans l'application s'ajuste automatiquement en fonction de la distance de déplacement attendue.
C'est tout IQKeyboardManager fait pour vous avec _/NO LINE OF CODE vraiment !! seulement besoin de glisser-déposer le fichier source lié au projet. IQKeyboardManager prend également en charge Orientation du périphérique, Gestion automatique UIToolbar, KeybkeyboardDistanceFromTextField et bien plus que vous ne le pensez.
J'ai mis en place une sous-classe universelle UIScrollView
, UITableView
et même UICollectionView
qui se charge de déplacer tous les champs de texte qu'elle contient hors du chemin du clavier.
Lorsque le clavier est sur le point d'apparaître, la sous-classe trouve la sous-vue sur le point d'être modifiée et ajuste son cadre et son contenu afin de s'assurer que cette vue est visible, avec une animation correspondant à la fenêtre contextuelle du clavier. Lorsque le clavier disparaît, il rétablit sa taille précédente.
Cela devrait fonctionner avec pratiquement n'importe quelle configuration, soit une interface basée sur UITableView
, soit une interface composée de vues placées manuellement.
Voici la solution: pour déplacer les champs de texte hors du chemin du clavier
Pour Swift Programmeurs:
Cela fera tout pour vous, il suffit de les mettre dans votre classe de contrôleur de vue et d'implémenter la variable UITextFieldDelegate
dans votre contrôleur de vue et de définir le délégué de textField sur self
textField.delegate = self // Setting delegate of your UITextField to self
Implémentez les méthodes de rappel du délégué:
func textFieldDidBeginEditing(textField: UITextField) {
animateViewMoving(true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
animateViewMoving(false, moveValue: 100)
}
// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
let movementDuration:NSTimeInterval = 0.3
let movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
Il y a déjà beaucoup de réponses, mais aucune des solutions ci-dessus ne contenait toutes les astuces de positionnement sophistiquées requises pour une animation "parfaite", sans bug, avec compatibilité ascendante et sans scintillement. (bug lors de l'animation d'images/bornes et de contentOffset ensemble, différentes orientations d'interface, clavier partagé iPad, ...)
Laissez-moi partager ma solution:
(en supposant que vous ayez configuré UIKeyboardWill(Show|Hide)Notification
)
// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrameInWindow;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];
// the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];
CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);
// this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_scrollView.contentInset = newContentInsets;
_scrollView.scrollIndicatorInsets = newContentInsets;
/*
* Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
* that should be visible, e.g. a purchase button below an amount text field
* it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
*/
if (_focusedControl) {
CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any Nice visual offset between control and keyboard or control and top of the scroll view.
CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.Origin.y - _scrollView.contentOffset.y;
CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;
// this is the visible part of the scroll view that is not hidden by the keyboard
CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;
if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
// scroll up until the control is in place
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);
// make sure we don't set an impossible offset caused by the "Nice visual offset"
// if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
} else if (controlFrameInScrollView.Origin.y < _scrollView.contentOffset.y) {
// if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
CGPoint newContentOffset = _scrollView.contentOffset;
newContentOffset.y = controlFrameInScrollView.Origin.y;
[_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
}
}
[UIView commitAnimations];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
// if we have no view or are not visible in any window, we don't care
if (!self.isViewLoaded || !self.view.window) {
return;
}
NSDictionary *userInfo = notification.userInfo;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
// undo all that keyboardWillShow-magic
// the scroll view will adjust its contentOffset apropriately
_scrollView.contentInset = UIEdgeInsetsZero;
_scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
[UIView commitAnimations];
}
Shiun a déclaré: "En fait, je pense qu'UIScrollView introduit implicitement implicitement le UITextField actuellement édité dans la fenêtre visible" Cela semble être vrai pour iOS 3.1.3, mais pas pour 3.2, 4.0 ou 4.1. J'ai dû ajouter un scrollRectToVisible explicite afin de rendre UITextField visible sur iOS> = 3.2.
Une chose à considérer est de savoir si vous voulez jamais utiliser une UITextField
seule. Je n’ai rencontré aucune application iPhone bien conçue qui utilise réellement UITextFields
en dehors de UITableViewCells
.
Ce sera un travail supplémentaire, mais je vous recommande de mettre en œuvre toutes les vues de saisie de données sous forme de vues de table. Ajoutez une UITextView
à votre UITableViewCells
.
This document détaille une solution à ce problème. Consultez le code source sous "Déplacer le contenu situé sous le clavier". C'est assez simple.
EDIT: Remarqué il y a un petit problème dans l'exemple. Vous voudrez probablement écouter UIKeyboardWillHideNotification
au lieu de UIKeyboardDidHideNotification
. Sinon, la vue de défilement derrière le clavier sera tronquée pendant toute la durée de l'animation de fermeture du clavier.
La solution la plus simple trouvée
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
Petit correctif qui fonctionne pour de nombreux UITextFields
#pragma mark UIKeyboard handling
#define kMin 150
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if (currTextField) {
[currTextField release];
}
currTextField = [sender retain];
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y + currTextField.frame.Origin. y >= kMin) {
[self setViewMovedUp:YES];
}
}
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's Origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.Origin.y = kMin - currTextField.frame.Origin.y ;
}
else
{
// revert back to the normal state.
rect.Origin.y = 0;
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)notif
{
//keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
if ([currTextField isFirstResponder] && currTextField.frame.Origin.y + self.view.frame.Origin.y >= kMin)
{
[self setViewMovedUp:YES];
}
else if (![currTextField isFirstResponder] && currTextField.frame.Origin.y + self.view.frame.Origin.y < kMin)
{
[self setViewMovedUp:NO];
}
}
- (void)keyboardWillHide:(NSNotification *)notif
{
//keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
if (self.view.frame.Origin.y < 0 ) {
[self setViewMovedUp:NO];
}
}
- (void)viewWillAppear:(BOOL)animated
{
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
}
- (void)viewWillDisappear:(BOOL)animated
{
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
Le code de RPDP déplace avec succès le champ de texte hors du chemin du clavier. Mais lorsque vous faites défiler vers le haut après avoir utilisé et supprimé le clavier, le haut a été défilé vers le haut. Cela est vrai pour le simulateur et le périphérique. Pour lire le contenu en haut de cette vue, il faut recharger la vue.
Son code suivant n'est-il pas censé ramener la vue?
else
{
// revert back to the normal state.
rect.Origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
Je ne suis pas sûr que le déplacement de la vue soit la bonne approche, je l'ai fait différemment, en redimensionnant UIScrollView Je l'ai expliqué en détail sur un petit article
Pour rétablir l'état de visualisation d'origine, ajoutez:
-(void)textFieldDidEndEditing:(UITextField *)sender
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.Origin.y < 0)
{
[self setViewMovedUp:NO];
}
}
Il y a tellement de solutions, mais j'ai passé quelques heures avant que ça commence à fonctionner. Donc, je mets ce code ici (il suffit de coller dans le projet, aucune modification nécessaire):
@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
UITextField* activeField;
UIScrollView *scrollView;
}
@end
- (void)viewDidLoad
{
[super viewDidLoad];
scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
//scrool view must be under main view - swap it
UIView* natView = self.view;
[self setView:scrollView];
[self.view addSubview:natView];
CGSize scrollViewContentSize = self.view.frame.size;
[scrollView setContentSize:scrollViewContentSize];
[self registerForKeyboardNotifications];
}
- (void)viewDidUnload {
activeField = nil;
scrollView = nil;
[self unregisterForKeyboardNotifications];
[super viewDidUnload];
}
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
-(void)unregisterForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect frame = self.view.frame;
frame.size.height -= kbSize.height;
CGPoint fOrigin = activeField.frame.Origin;
fOrigin.y -= scrollView.contentOffset.y;
fOrigin.y += activeField.frame.size.height;
if (!CGRectContainsPoint(frame, fOrigin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y + activeField.frame.size.height - frame.size.height);
[scrollView setContentOffset:scrollPoint animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
[scrollView setContentOffset:CGPointZero animated:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
P.S: J'espère que le code aidera quelqu'un à produire l'effet désiré rapidement. (Xcode 4.5)
@ user271753
Pour que votre vue redevienne comme avant, ajoutez:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
[self setViewMovedUp:NO];
return YES;
}
Essayez ce petit truc.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = textField.frame.Origin.y / 2; // Tweak as needed
const float movementDuration = 0.3f; // Tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
Il n’est pas nécessaire de faire défiler la vue pour pouvoir déplacer le cadre de la vue. Vous pouvez modifier le cadre d'une vue viewcontroller's
de sorte que la vue entière monte juste assez pour que le champ de texte du premier répondant soit placé au-dessus du clavier. Quand j'ai rencontré ce problème, j'ai créé une sous-classe de UIViewController
qui fait cela. Il observe que le clavier va apparaître une notification et trouve la sous-vue du premier intervenant et (si nécessaire) il anime la vue principale vers le haut, suffisamment pour que le premier intervenant se trouve au-dessus du clavier. Lorsque le clavier se cache, la vue est animée.
Pour utiliser cette sous-classe, faites de votre contrôleur de vue personnalisé une sous-classe de GMKeyboardVC et il hérite de cette fonctionnalité (assurez-vous simplement que si vous implémentez viewWillAppear
et viewWillDisappear
, ils doivent appeler super). La classe est sur github .
Conformément à the docs , à partir d’iOS 3.0, la classe UITableViewController
redimensionne et repositionne automatiquement sa vue sous forme de tableau lorsqu’il y a une modification en ligne des champs de texte. Je pense qu'il n'est pas suffisant de placer le champ de texte dans une UITableViewCell
comme certains l'ont indiqué.
De les docs :
Un contrôleur de vue de tableau prend en charge la modification en ligne des lignes de vue de tableau; si, par exemple, les lignes comportent des champs de texte incorporés en mode édition, spécifiez fait défiler la ligne en cours d'édition au-dessus du clavier virtuel qui est affiché.
Voici la solution de hack que j'ai proposée pour une mise en page spécifique. Cette solution est similaire à celle de Matt Gallagher dans la mesure où elle fait défiler une section. Je suis encore nouveau dans le développement iPhone et je ne connais pas bien le fonctionnement des mises en page. Ainsi, ce hack.
Mon implémentation devait prendre en charge le défilement lorsque vous cliquez dans un champ, ainsi que le défilement lorsque l'utilisateur sélectionne ensuite le clavier.
J'ai eu un UIView avec une hauteur de 775. Les contrôles sont répartis essentiellement par groupes de 3 sur un grand espace. Je me suis retrouvé avec la mise en page suivante IB.
UIView -> UIScrollView -> [UI Components]
Voici le hack
Je règle la hauteur UIScrollView sur 500 unités plus grandes que la disposition réelle (1250). J'ai ensuite créé un tableau avec les positions absolues vers lesquelles je dois faire défiler et une fonction simple pour les obtenir en fonction du numéro d'étiquette IB.
static NSInteger stepRange[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};
NSInteger getScrollPos(NSInteger i) {
if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
return 0 ;
return stepRange[i] ;
}
Il ne vous reste plus qu'à utiliser les deux lignes de code suivantes dans textFieldDidBeginEditing et textFieldShouldReturn (le dernier si vous créez un champ de navigation suivant)
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
Un exemple.
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger nextTag = textField.tag + 1;
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {
[nextResponder becomeFirstResponder];
CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
[self.scrollView setContentOffset:point animated:YES] ;
}
else{
[textField resignFirstResponder];
}
return YES ;
}
Cette méthode ne "retourne" pas comme les autres méthodes. Ce n'était pas une exigence. Encore une fois, c’était pour un UIView assez «grand», et je n’ai pas eu les jours pour apprendre les moteurs de disposition internes.
Ici j'ai trouvé la solution la plus simple pour gérer le clavier.
Vous devez simplement copier-coller ci-dessous le code exemple et modifier votre champ de texte ou toute vue que vous souhaitez déplacer.
Étape 1
Il suffit de copier-coller ci-dessous deux méthodes dans votre contrôleur
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)deregisterFromKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Étape 2
enregistrer et désenregistrer les notifications du clavier dans viewWillAppear et viewWillDisappear méthodes, respectivement.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self registerForKeyboardNotifications];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];
}
Étape 3
Voici la partie âme, remplacez simplement votre champ de texte et changez hauteur combien vous voulez bouger à la hausse.
- (void)keyboardWasShown:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//you need replace your textfield instance here
CGPoint textFieldOrigin = self.tokenForPlaceField.frame.Origin;
CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;
CGRect visibleRect = self.view.frame;
visibleRect.size.height -= currentKeyboardSize.height;
if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
{
//you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below
CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
[self.scrollView setContentOffset:scrollPoint animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification
{
[self.scrollView setContentOffset:CGPointZero animated:YES];
}
Référence: Eh bien, Merci d'apprécier ce gars , qui a partagé cette belle solution de code snip, clean.
J'espère que cela serait sûrement utile, quelqu'un là-bas.
Swift 4.
Vous pouvez facilement monter et descendre UITextField
ou UIView
avec UIKeyBoard
avec Animation
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var textField: UITextField!
@IBOutlet var chatView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textField.resignFirstResponder()
}
@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
print("deltaY",deltaY)
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.chatView.frame.Origin.y+=deltaY // Here You Can Change UIView To UITextField
},completion: nil)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Je cherchais un bon tutoriel pour les débutants sur le sujet, j'ai trouvé le meilleur tutoriel ici .
Dans l'exemple MIScrollView.h
au bas du didacticiel, veillez à laisser un espace à
@property (nonatomic, retain) id backgroundTapDelegate;
comme tu vois.
Lorsque UITextField
est dans une UITableViewCell
, le défilement doit être configuré automatiquement.
Si ce n'est pas le cas, c'est probablement à cause d'un code incorrect/de la configuration de la table.
Par exemple, lorsque j'ai rechargé ma longue table avec un UITextField
au bas de la manière suivante,
-(void) viewWillAppear:(BOOL)animated
{
[self.tableview reloadData];
}
puis mon champ de texte au bas a été masqué par le clavier qui est apparu lorsque j'ai cliqué à l'intérieur du champ de texte.
Pour résoudre ce problème, je devais le faire -
-(void) viewWillAppear:(BOOL)animated
{
//add the following line to fix issue
[super viewWillAppear:animated];
[self.tableview reloadData];
}
Utilisez cette troisième partie, vous n'avez pas besoin d'écrire même une ligne
https://github.com/hackiftekhar/IQKeyboardManager
téléchargez le projet et faites glisser IQKeyboardManager dans votre projet . Si vous rencontrez un problème, veuillez lire le document README.
Les gars vraiment son enlever la migraine pour gérer le clavier ..
Merci et bonne chance!
Note : cette réponse suppose que votre textField est dans un scrollView.
Je préfère traiter cela avec scrollContentInset et scrollContentOffset au lieu de jouer avec les cadres de ma vue.
D'abord écoutons les notifications du clavier
//call this from viewWillAppear
-(void)addKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
[[NSNotificationCenter default
Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
La prochaine étape consiste à conserver une propriété représentant le premier répondant actuel (UITextfield/UITextVIew contenant le clavier).
Nous utilisons les méthodes déléguées pour définir cette propriété. Si vous utilisez un autre composant, vous aurez besoin de quelque chose de similaire.
Notez que pour textfield, nous l'avons défini dans didBeginEditing et pour textView dans shouldBeginEditing. Ceci est dû au fait que textViewDidBeginEditing est appelé après UIKeyboardWillShowNotification pour une raison quelconque.
-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
self.currentFirstResponder = textView;
return YES;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
self.currentFirstResponder = textField;
}
Enfin, voici la magie
- (void)keyboardWillShow:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
/*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
if(self.currentFirstResponder){
//keyboard Origin in currentFirstResponderFrame
CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.Origin fromView:nil];
float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);
//only scroll the scrollview if keyboard overlays the first responder
if(spaceBetweenFirstResponderAndKeyboard>0){
//if i call setContentOffset:animate:YES it behaves differently, not sure why
[UIView animateWithDuration:0.25 animations:^{
[self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
}];
}
}
//set bottom inset to the keyboard height so you can still scroll the whole content
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}
C'est la solution utilisant Swift.
import UIKit
class ExampleViewController: UIViewController, UITextFieldDelegate {
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var textField1: UITextField!
@IBOutlet var textField2: UITextField!
@IBOutlet var textField3: UITextField!
@IBOutlet var textField4: UITextField!
@IBOutlet var textField5: UITextField!
var activeTextField: UITextField!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
self.textField1.delegate = self
self.textField2.delegate = self
self.textField3.delegate = self
self.textField4.delegate = self
self.textField5.delegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.registerForKeyboardNotifications()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.unregisterFromKeyboardNotifications()
}
// MARK: - Keyboard
// Call this method somewhere in your view controller setup code.
func registerForKeyboardNotifications() {
let center: NSNotificationCenter = NSNotificationCenter.defaultCenter()
center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}
func unregisterFromKeyboardNotifications () {
let center: NSNotificationCenter = NSNotificationCenter.defaultCenter()
center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
// Called when the UIKeyboardDidShowNotification is sent.
func keyboardWasShown (notification: NSNotification) {
let info : NSDictionary = notification.userInfo!
let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size
let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.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, self.activeTextField.frame.Origin) ) {
self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
}
}
// Called when the UIKeyboardWillHideNotification is sent
func keyboardWillBeHidden (notification: NSNotification) {
let contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
// MARK: - Text Field
func textFieldDidBeginEditing(textField: UITextField) {
self.activeTextField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
self.activeTextField = nil
}
}
Vous devez ajouter scrollview par programme avec une taille d'image spécifique. Vous devez ajouter UIScrollViewDelegate dans un fichier .h. Vous devez activer scrollview pour que vous deviez écrire ensuite dans viewDidLoad ().
scrollview.scrollEnabled=YES;
scrollview.delegate=self;
scrollview.frame = CGRectMake(x,y,width,height);
//---set the content size of the scroll view---
[scrollview setContentSize:CGSizeMake(height,width)];
De cette façon, vous pouvez ajouter vos valeurs x, y, largeur et hauteur ... Je pense que cela vous aidera.
Essaye ça:
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
if ([sender isEqual:self.m_Sp_Contact])
{
[self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];
}
}
Swift 2.0:
Ajoutez un UIScrollView et ajoutez textFields au-dessus. Faites des références de storyboard à VC.
@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var scrollView: UIScrollView!
Ajoutez ces méthodes: UITextFieldDelegate & UIScrollViewDelegate.
//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool {
if(username.returnKeyType == UIReturnKeyType.Default) {
password.becomeFirstResponder()
}
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
dispatch_async(dispatch_get_main_queue()) {
let scrollPoint:CGPoint = CGPointMake(0,textField.frame.Origin.y/4)
self.scrollView!.setContentOffset(scrollPoint, animated: true);
}
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
}
return true
}
override func touchesBegan(touches: Set<UITouch>,
withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.scrollView.scrollEnabled = true
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)
})
}
}
Voici une bibliothèque gratuite pour la manipulation du clavier Keyboard-Handling-in-iPhone-Applications . Vous devez écrire une seule ligne de code:
[AutoScroller addAutoScrollTo:scrollView];
C'est génial pour gérer le clavier dans les formulaires
Je pense que la meilleure approche consiste à utiliser la programmation orientée protocole si vous utilisez Swift.
Tout d'abord, vous devez créer un protocole KeyboardCapable
, qui donne à tout UIViewController qui le respecte la possibilité d'enregistrer et de désenregistrer les observateurs au clavier:
import Foundation
import UIKit
protocol KeyboardCapable: KeyboardAnimatable {
func keyboardWillShow(notification: NSNotification)
func keyboardWillHide(notification: NSNotification)
}
extension KeyboardCapable where Self: UIViewController {
func registerKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
}
func unregisterKeyboardNotifications() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
}
Vous avez remarqué le mot clé KeyboardAnimatable
superflu dans le code ci-dessus. C'est juste le nom du prochain protocole que nous devons créer:
import Foundation
import UIKit
protocol KeyboardAnimatable {
}
extension KeyboardAnimatable where Self: UIViewController {
func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {
UIView.animateWithDuration(duration, animations: { () -> Void in
self.view.frame = CGRectMake(view.frame.Origin.x, -height, view.bounds.width, view.bounds.height)
}, completion: nil)
}
func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {
UIView.animateWithDuration(duration, animations: { () -> Void in
self.view.frame = CGRectMake(view.frame.Origin.x, 0.0, view.bounds.width, view.bounds.height)
}, completion: nil)
}
}
Ce protocole KeyboardAnimatable
donne à tout UIViewController le conformant deux méthodes qui animeront la vue entière de haut en bas, respectivement.
Très bien, si KeyboardCapable
est conforme à KeyboardAnimatable
, tous les UIViewController conformes à KeyboardCapable
sont également conformes à KeyboardAnimatable
. C'est super.
Voyons une UIViewController
conforme KeyboardCapable
et réagissant aux événements de clavier:
import Foundation
import UIKit
class TransferConfirmViewController: UIViewController, KeyboardCapable {
//MARK: - LIFE CYCLE
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
registerKeyboardNotifications()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
unregisterKeyboardNotifications()
}
//MARK: - NOTIFICATIONS
//MARK: Keyboard
func keyboardWillShow(notification: NSNotification) {
let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
performKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)
}
func keyboardWillHide(notification: NSNotification) {
let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
performKeyboardHideFullViewAnimation(withDuration: animationDuration)
}
}
Maintenant, votre UIViewController
répondra aux événements de clavier et s'animera en conséquence.
Remarque: Si vous souhaitez une animation personnalisée plutôt que Push ou extraire la vue, vous devez définir des méthodes personnalisées sur le protocole KeyboardAnimatable
ou les exécuter sur des fonctions KeyboardCapable
. C'est à vous.
Une solution beaucoup plus élégante consiste à utiliser une sous-classe UIView
(bien que cela ne soit pas toujours approprié) et à recalculer toutes vos sous-vues lors de la modification de la trame d'un parent (et soyez intelligent: recalculez-les uniquement si la nouvelle taille de la trame a changé, c'est-à-dire CGRectEqualToRect
pour comparer la nouvelle image lorsque vous remplacez setFrame
et AVANT d'appeler [super setFrame:frame_]
). Le seul problème avec ceci est que la UIViewController
que vous avez l'intention d'utiliser devrait probablement écouter les événements de clavier (ou vous pouvez le faire dans la UIView
elle-même, pour une encapsulation pratique). Mais seulement les UIKeyboardWillShowNotification
et UIKeyboardWillHideNotification
. C'est juste pour que tout se passe bien (si vous attendez que CG l'appelle, vous aurez un moment de chaos).
Cela a l’avantage de construire une sous-classe UIView
qui fait ce qu’il faut faire, de toute façon.
L’implémentation naïve consisterait à écraser drawRect:
(ne pas), une meilleure serait simplement d’utiliser layoutSubviews
(puis dans UIViewController
, ou ce que vous ne pouvez pas appeler [view setNeedsLayout
] dans une méthode SINGLE qui est appelée pour show ou cacher).
Cette solution évite de coder en dur un décalage de clavier (ce qui changera s’ils ne sont pas fractionnés, etc.) et signifie également que votre vue pourrait être une sous-vue de beaucoup d’autres vues tout en répondant correctement.
Ne codifiez pas quelque chose comme ça à moins qu'il n'y ait pas d'autre solution. Le système d'exploitation vous donne suffisamment d'informations, si vous avez bien fait les choses, qu'il vous suffit de redessiner intelligemment (en fonction de votre nouvelle taille frame
). Ceci est beaucoup plus propre et la façon dont vous devrait faire des choses. (Il peut y avoir une approche encore meilleure, cependant.)
À votre santé.
C'est très simple, il suffit de mettre le code suivant dans votre classe et de le personnaliser si vous en avez besoin.
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Show Keyboard
self.view.frame = CGRectMake(self.view.frame.Origin.x,
self.view.frame.Origin.y-50,
self.view.frame.size.width,
self.view.frame.size.height);
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
// Hide keyboard
self.view.frame = CGRectMake(self.view.frame.Origin.x,
self.view.frame.Origin.y+50,
self.view.frame.size.width,
self.view.frame.size.height);
}
Vous pouvez également utiliser des méthodes de délégation textfield. Vérifiez ci-dessous le code. Cela fonctionne pour moi quand textfield est placé sur la vue de défilement.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if(textField == answer)
{
CGPoint cPoint = textField.frame.Origin;
[scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];
}
}
Remarque: Vous devez modifier la valeur cPoint.y - 100 en fonction de votre vue.
Voici ma version utilisant autolayout:
L'idée est simplement d'intégrer votre vue contenant des champs de texte/vue de texte dans un UIScrollView, de définir une contrainte du bas vers son supérieur, de créer un point de vente et de la mettre à jour en fonction de la hauteur du clavier à l'aide de notifications . Ceci est basé sur un exemple Apple here et note technique Apple sur UIScrollView utilisant AutoLayout here .
1) Intégrez votre vue V dans un fichier UIScrollView S: Si vous avez déjà défini vos constantes et sous-vues, vous pouvez copier/coller votre vue et vos sous-vues dans la vue du ViewController, puis l’intégrer à l’aide du menu Edit -> embed et enfin supprimer les vues copiées.)
2) Définissez les contraintes suivantes:
S suivi de la vue d'ensemble: 0
V haut espace pour superview: 0
V menant espace à superview: 0
V égale largeur à S
Dernière sous-vue V inférieure à la vue d'ensemble: 20
3) Créez un point de vente à partir de la dernière contrainte sur votre contrôleur de vue
4) Utilisez le code suivant:
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;
// ...
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Handle keyboard
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;
[self.view layoutIfNeeded];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
self.bottomSpaceToContentView.constant = kBottomMargin;
[self.view layoutIfNeeded];
}
Et tadaaaaa, ça marche!
Il existe de nombreuses réponses disponibles indiquant l'approche. J'ai adopté la même approche mais la mise en œuvre n'est pas bonne.
Voici la idée de base . J'ai apporté des modifications à la méthode keyboardWasShown.
{
// Obtain keyboard Info
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
// Obtain ScrollView Info w.r.t. top View
CGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];
// Depending upon your screen Ui, Scroll View's bottom Edge might be at some offset from screen's bottom
// Calculate the exact offset
int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.Origin.y + scrollViewRect.size.height);
int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;
// We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now
// But we should store these, so that we can restore the Insets when Keyboard is gone
// origInsets = self.scrollView.contentInset;
// Set the new Insets for ScrollView
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// Visible frame (not overlapped by Keyboard)
CGRect visibleFrame = self.view.frame;
visibleFrame.size.height -= keyboardRect.size.height;
// Get the Rect for Textfield w.r.t self.view
CGRect activeFieldFrame = self.activeField.frame;
activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];
// Check if the TextField is Visible or not
if (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {
// Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View
[self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}
}
Et ajoutez cette méthode pour initialiser l’activeField
- (IBAction)textFieldDidBeginEditing:(UITextField *)sender
{
self.activeField = sender;
}
Ceci est un calcul de décalage indépendant de l'appareil. Obtient la hauteur de chevauchement entre le clavier et le champ de texte:
func keyboardShown(notification: NSNotification) {
let info = notification.userInfo!
let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!
let rawFrame = value.CGRectValue
let keyboardFrame = view.convertRect(rawFrame, fromView: nil)
let screenHeight = UIScreen.mainScreen().bounds.size.height;
let Ylimit = screenHeight - keyboardFrame.size.height
let textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)
self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit
if(self.keyboardHeight>0){
self.animateViewMoving(true, moveValue: keyboardHeight!)
}else{
keyboardHeight=0
}
}
keyBoardHeight est l'offset.
https://github.com/michaeltyson/TPKeyboardAvoiding téléchargez ce fichier et ajoutez une classe personnalisée comme ceci dans votre vue tableau, il gérera tout ce que vous n'avez pas besoin de faire. éviter le clavier
voici une catégorie UITextfield (et d’autres champs similaires) que j’ai créée pour que le champ de texte évite le clavier, vous devriez pouvoir le déposer dans votre contrôleur de vue tel quel et cela devrait fonctionner. Il déplace la totalité de l'écran vers le haut de sorte que le champ de texte actuel soit au-dessus du clavier avec des animations
#import "UIView+avoidKeyboard.h"
#import "AppDelegate.h"
@implementation UIView (avoidKeyboard)
- (void) becomeFirstResponder {
if(self.isFirstResponder)
return;
[super becomeFirstResponder];
if ([self isKindOfClass:[UISearchBar class]] ||
[self isKindOfClass:[UITextField class]] ||
[self isKindOfClass:[UITextView class]])
{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
CGRect screenBounds = appDelegate.window.frame;
CGFloat keyboardHeight;
CGFloat keyboardY;
CGFloat viewsLowestY;
CGPoint Origin = [self.superview convertPoint:self.frame.Origin toView:appDelegate.window]; //get this views Origin in terms of the main screens bounds
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the Origin instead of the y
keyboardHeight = 216;
keyboardY = screenBounds.size.height - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
viewsLowestY = Origin.y + self.frame.size.height; //find the lowest point of this view
}
else {
keyboardHeight = 162;
keyboardY = screenBounds.size.width - keyboardHeight;
viewsLowestY = Origin.x + self.frame.size.height;
}
CGFloat difference = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding
if (difference > 0){ //move screen up if there is an overlap
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
CGRect frame = appDelegate.window.frame;
if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
frame.Origin.y -= difference;
}
else {
frame.Origin.x -= difference;
}
appDelegate.window.frame = frame;
}
completion:nil];
}
}
}
//look at appDelegate to see when the keyboard is hidden
@end
Dans votre appDéléguer, ajoutez cette fonction
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions
...
- (void)keyboardHides:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
[window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
} completion:nil];
}
S'il vous plaît suivez ces étapes.
1) Déclarez la variable suivante dans le fichier .h.
{
CGFloat animatedDistance;
}
2) Déclarez les constantes suivantes dans le fichier .m.
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
3) Utilisez le délégué UITextField pour déplacer le clavier vers le haut ou le bas.
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.Origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.Origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
J'emballe tout dans une classe. Appelez simplement ces lignes de code lorsque votre contrôleur de vue est chargé:
- (void)viewDidLoad {
[super viewDidLoad];
KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
[injectView injectToView:self.view withRootView:self.view];
}
Voici le lien du projet exemple:
https://github.com/caohuuloc/KeyboardInsetScrollView
Je me suis récemment retrouvé dans un scénario similaire lorsque je travaillais sur une application de messagerie. J'ai créé un UIView personnalisé qui colle au haut du clavier et fait presque tout ce dont vous avez besoin automatiquement
http://www.thegameengine.org/wp-content/uploads/2013/11/message_composer_quad_1.jpg
L'idée derrière ce projet était de créer quelque chose qui fonctionne de manière similaire à la vue de composition de iMessage, AKA:
Afin de redimensionner/reconfigurer votre UIScrollView, vous souhaiterez utiliser la méthode de délégation facultative suivante:
- (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;
Il sera appelé chaque fois que le cadre est modifié (redimensionné, repositionné, pivoté) et fournira également la durée de l'animation. Vous pouvez utiliser ces informations pour redimensionner le cadre et les éléments de contenu de votre UIScrollView selon vos besoins.
Ajoutez simplement ceci à votre fichier pod -> pod 'IQKeyboardManager'
Ca y est, gère tout le clavier, les vues de défilement et tout!
Vous n'avez pas besoin de coder quoi que ce soit, vous ne pourriez pas trouver une meilleure solution!
Il possède une extension qui gère l’affichage des champs de texte, le décalage d’écran, les flèches suivante et précédente s'il existe plusieurs champs de texte.
Il a également un bouton fait sur commande, qui peut être supprimé.
J'ai trouvé que c'était la meilleure solution, suivez le code ci-dessous:
Joignez ce qui suit à votre contrainte Vertical Space - Bottom Layout Guide - TextField
.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;
Deuxièmement, ajoutez des observateurs pour les notifications au clavier.
- (void)observeKeyboard {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
Ajoutez ceci à votre viewDidLoad
[self observeKeyboard];
Enfin, les méthodes qui gèrent les changements de clavier.
- (void)keyboardWillShow:(NSNotification *)notification {
//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
kbHeight = 0;
height = 0;
self.textViewBottomConst.constant = height;
self.btnViewBottomConst.constant = height;
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [kbFrame CGRectValue];
CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];
int kbHeight = finalKeyboardFrame.size.height;
int height = kbHeight + self.textViewBottomConst.constant;
self.textViewBottomConst.constant = height;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.textViewBottomConst.constant = 10;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
Je sais que c'est trop tard, mais je voulais surtout partager avec les futurs visiteurs ma façon de le faire. Beaucoup de bonnes méthodes ont été partagées mais je n’ai pas aimé la façon dont l’interface utilisateur devient totalement mauvaise. Il existe une méthode simple qui implique deux parties: -
CGAffineTransform(TranslationX: x, TranslationY: y)
pour déplacer la vue créée au-dessus du clavier. Je sais que cela semble très simple, mais c’est vraiment efficace et soigné .
Une solution simple pour étendre UIViewController
Solution simple et avec dernière api d'animation. Si vous modifiez le fichier Origin.y par 215, vous pouvez le personnaliser selon la valeur qui vous convient.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (self.view.frame.Origin.y >= 0) {
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y-215, self.view.frame.size.width, self.view.frame.size.height);
}];
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (self.view.frame.Origin.y < 0) {
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y+215, self.view.frame.size.width, self.view.frame.size.height);
}];
}
}
Je voudrais prolonger la réponse de @sumanthkodi.
Comme certaines personnes l'ont indiqué, son approche ne fonctionne pas dans les nouvelles implémentations, car UIView ne se déplace pas lorsque vous utilisez contraintes .
J'ai édité le code comme suit (et porté à Swift 2.0) et j'espère que cela aidera certaines personnes:
1) Référencez la contrainte verticale de la vue que vous souhaitez déplacer vers le haut:
@IBOutlet var viewConstraint: NSLayoutConstraint!
Assurez-vous de référencer cette variable dans votre scénario avec la contrainte.
2) Ajoutez le délégué et implémentez les écouteurs. C'est la même implémentation que précédemment:
class YourViewController: UIViewController, UITextFieldDelegate {
...
func textFieldDidBeginEditing(textField: UITextField) {
animateTextField(textField, up: true)
}
func textFieldDidEndEditing(textField: UITextField) {
animateTextField(textField, up: false)
}
...
}
3) Ajoutez votre méthode d’animation animateTextField
à la classe YourViewController
. Définissez la valeur de contrainte temporaire selon vos besoins.
func animateTextField(textfield: UITextField, up: Bool) {
let originalConstraint = 50
let temporaryConstraint = 0
let movementDuration = 0.3
let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)
containerViewConstraint.constant = constraint
UIView.animateWithDuration(movementDuration) {
self.view.layoutIfNeeded()
}
}
Cela fonctionnera parfaitement. La vue de défilement s'ajustera automatiquement par la position du champ de texte.Je suis sûr que vous vous sentirez bien
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;
@interface LoginVC ()
{
CGFloat animatedDistance;
CGRect viewFrameKey;
}
//In ViewDidLoad
viewFrameKey=self.view.frame;
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFieldRect =
[self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect =
[self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.Origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator =
midline - viewRect.Origin.y
- MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator =
(MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
* viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.Origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrameKey];
[UIView commitAnimations];
}
Je viens de trouver cette classe:
https://github.com/OliverLetterer/SLScrollViewKeyboardSupport
Et jusqu'à présent, cela fonctionne très bien sur iPhone, y compris les animations et le décalage correct.
Pour l'utiliser, ajoutez simplement à viewDidLoad
:
self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
Une solution très légère pourrait utiliser KeyboardAnimator .
le projet a reçu l'exemple de mise en oeuvre, la documentation est toujours en cours ...
Utilisation appropriée :: Il a une implémentation spécifique pour UITextField et UITextView.
Limitation :: Il est entièrement sur objective-c, la version Swift sera bientôt disponible.
Ce morceau de code calculera le besoin de déplacement en fonction de la hauteur du clavier et de la profondeur du champ de texte. N'oubliez pas d'ajouter un délégué et d'hériter UITextFieldDelegate à votre en-tête.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[_tbxUsername resignFirstResponder];
[_tbxPassword resignFirstResponder];
}
- (void)textFieldDidBeginEditing:(UITextField *) textField
{
[self animateTextField:textField up:YES];
}
- (void)textFieldDidEndEditing:(UITextField *) textField
{
[self animateTextField:textField up:NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
int animatedDistance;
int moveUpValue = textField.frame.Origin.y+ textField.frame.size.height;
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = 236-(460-moveUpValue-5);
}
else
{
animatedDistance = 182-(320-moveUpValue-5);
}
if(animatedDistance>0)
{
const int movementDistance = animatedDistance;
const float movementDuration = 0.3f;
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: nil context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
}
Délégué à ajouter à ViewDidLoad
_tbxUsername.delegate = self;
_tbxPassword.delegate = self;
Sur votre ViewController:
@IBOutlet weak var usernameTextfield: UITextField!
@IBOutlet weak var passwordTextfield: UITextField!
@IBOutlet weak var loginScrollView: UIScrollView!
override func viewWillAppear(animated: Bool) {
loginScrollView.scrollEnabled = false
}
Ajouter des délégués TextField.
//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool
{
if (usernameTextfield.resignFirstResponder())
{
passwordTextfield.becomeFirstResponder()
}
textField.resignFirstResponder();
loginScrollView!.setContentOffset(CGPoint.zero, animated: true);
loginScrollView.scrollEnabled = false
return true
}
func textFieldDidBeginEditing(textField: UITextField)
{
loginScrollView.scrollEnabled = true
if (textField.tag == 1 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
{
let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.Origin.y/6.4);
loginScrollView!.setContentOffset(scrollPoint, animated: true);
}
else if (textField.tag == 2 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
{
let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.Origin.y/6.0);
loginScrollView!.setContentOffset(scrollPoint, animated: true);
}
}
func textFieldDidEndEditing(textField: UITextField)
{
loginScrollView!.setContentOffset(CGPointZero,animated: true);
}
Afficher la vue de défilement en vue
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint point;
if(textField == txtEmail){
// -90 is for my you can change as per your postion
point = CGPointMake(0, textField.frame.Origin.y - 90);
}
else if (textField == txtContact){
point = CGPointMake(0, textField.frame.Origin.y - 90);
}
[scrollV setContentOffset:point animated:YES];
}
Veuillez ajouter ces lignes dans la méthode de délégation de champ de texte pour faire défiler vers le haut dans iPad.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeTextfield = textField;
CGPoint pt;
CGRect rc = [textField bounds];
rc = [textField convertRect:rc toView:scrlView];
pt = rc.Origin;
pt.x = 0;
pt.y -= 100;
[scrlView setContentOffset:pt animated:YES];
scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.Origin.y+button.frame.size.height + 8 + 370);
}
Essayez la bibliothèque IQKeyboard.
Cela déplacera automatiquement le champ de texte vers le haut.
Ceci peut être simplement réalisé avec les lignes de code ci-dessous en utilisant des contraintes
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];
}
- (void)viewDidDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super viewDidDisappear:animated];
}
- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat height = keyboardFrame.size.height;
self.constraintToAdjust.constant = height; UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
if (animationCurve == UIViewAnimationCurveEaseIn) {
animationOptions |= UIViewAnimationOptionCurveEaseIn;
}
else if (animationCurve == UIViewAnimationCurveEaseInOut) {
animationOptions |= UIViewAnimationOptionCurveEaseInOut;
}
else if (animationCurve == UIViewAnimationCurveEaseOut) {
animationOptions |= UIViewAnimationOptionCurveEaseOut;
}
else if (animationCurve == UIViewAnimationCurveLinear) {
animationOptions |= UIViewAnimationOptionCurveLinear;
}
[UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
Nous devrions calculer la zone d'intersection exacte (le cadre du clavier et celui du champ de texte) qui est masquée, puis nous devrions changer le cadre de la vue.
Ici, je donne un exemple complet.
Déclarant 3 varible
#define PADDING 10
@interface PKViewController () @property (nonatomic, assign) CGRect originalViewFrame; //original view's frame @property (nonatomic, strong) UITextField *activeTextField; // current text field @property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard @end
Stocker le cadre d'origine
- (void)viewDidLoad {
[super viewDidLoad];
_originalViewFrame = self.view.frame;
}
Ajoutez votre contrôleur de vue en tant qu'observateur pour la notification au clavier
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
Supprimer l'observateur
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Stocker la zone couverte par le clavier quand il apparaît et le définir sur CGRectZero quand il disparaît
- (void)keyboardWasShown:(NSNotification *)notification{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
_keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
[self moveTextFieldUP];
}
- (void) keyboardWillHide:(NSNotification *)notification{
_keyBoardRect = CGRectZero;
[self setDefaultFrame];
}
Stocker le champ de texte actif
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
_activeTextField = textField;
//When keyboard is already present but the textfield is hidden. Case:When return key of keyboard makes the next textfield as first responder
if (!CGRectIsEmpty(_keyBoardRect)) {
[self moveTextFieldUP];
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
Maintenant, nous devrions changer le cadre de la vue
- (void)moveTextFieldUP{
CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.Origin.y, _activeTextField.frame.size.width, _activeTextField.frame.Origin.y+_activeTextField.frame.size.height);
if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
CGFloat newY = _originalViewFrame.Origin.y - intersectRect.size.height;
CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:newFrame];
}];
NSLog(@"Intersect");
}
}
- (void)setDefaultFrame {
[UIView animateWithDuration:0.3 animations:^{
[self.view setFrame:_originalViewFrame];
}];
}
Beaucoup de réponses ici, mais cela fonctionne et est beaucoup plus court que la plupart:
- (void)textFieldDidBeginEditing:(UITextField *)sender
{
UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's controller
const double dontHardcodeTheKeyboardHeight = 162;
double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;
if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)
[scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];
}
Cela peut être fait facilement et automatiquement si ce champ de texte est dans la cellule d'un tableau (même lorsque la table.scrollable = NO).
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
[self slideUp];
return YES;
}
-(BOOL) textFieldShouldEndEditing:(UITextField *)textField {
[self slideDown];
return YES;
}
#pragma mark - Slide Up and Down animation
- (void) slideUp {
[UIView beginAnimations:nil context:nil];
layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);
[UIView commitAnimations];
}
- (void) slideDown {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelay: 0.01];
layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);
[UIView commitAnimations];
}
Bien que ce fil ait suffisamment de réponses, je voudrais suggérer une manière beaucoup plus simple mais généralisée, tout comme Apple le prend en tenant compte de la hauteur du pavé numérique, ce qui est très utile lorsque nous utilisons une barre d’outils personnalisée au-dessus du clavier ici a quelques problèmes.
Voici mon approche (façon légèrement modifiée par Apple) -
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
}
c'est simple:-
Dans TextFieldDidBeginEditing: -
self.view.frame=CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y-150, self.view.frame.size.width, self.view.frame.size.height);
Dans TextFieldShouldEndEditing: -
self.view.frame=CGRectMake(self.view.frame.Origin.x, self.view.frame.Origin.y+150, self.view.frame.size.width, self.view.frame.size.height);
Avec IQKeyboardManager, UITextField et UITextView défilent automatiquement lorsque le clavier apparaît. Lien Git: https://github.com/hackiftekhar/IQKeyboardManager .
pod: pod 'IQKeyboardManager' # iOS8 et versions ultérieures
pod 'IQKeyboardManager', '3.3.7' # iOS7
Solution simple pour Scrollview avec TextFields est ci-dessous, pas besoin de contraintes ou champ de texte actif, etc.
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
registerForKeyboardNotifications();
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deregisterFromKeyboardNotifications();
}
//MARK:- KEYBOARD DELEGATE METHODS
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)
}
func keyboardWasShown(notification: NSNotification){
var info = notification.userInfo!
let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
var contentInset:UIEdgeInsets = self.scrRegister.contentInset
contentInset.bottom = (keyboardSize?.height)!
scrRegister.contentInset = contentInset
}
func keyboardWillBeHidden(notification: NSNotification)
{
var contentInset:UIEdgeInsets = self.scrRegister.contentInset
contentInset.bottom = 0
scrRegister.contentInset = contentInset
}
Veuillez suivre ces étapes, cela pourrait être utile . Placez une vue puis placez votre champ de texte sur cette vue et détectez l’événement par délégué lorsque votre clavier arrive, à cet instant, animez la vue vers le haut (vous pouvez attribuer une position pour cette vue également), votre vue irait jusqu’à cette position. Faites la même chose pour animer la vue.
Merci
Cela a fonctionné pour moi:
func setupKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWasShown(aNotification:NSNotification) {
let info = aNotification.userInfo
let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
let kbSize = infoNSValue.CGRectValue().size
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
var rect : CGRect = self.view.frame
rect.size.height -= kbSize.height
self.view.frame = rect
UIView.commitAnimations()
}
func keyboardWillBeHidden(aNotification:NSNotification) {
let info = aNotification.userInfo
let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
let kbSize = infoNSValue.CGRectValue().size
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
var rect : CGRect = self.view.frame
rect.size.height += kbSize.height
self.view.frame = rect
UIView.commitAnimations()
}
Si le champ de texte doit se trouver au bas de l'écran, la solution la plus magique est le remplacement suivant sur votre contrôleur de vue:
override var inputAccessoryView: UIView? {
return <yourTextField>
}
Nous pouvons utiliser le code donné pour Swift 4.1
let keyBoardSize = 80.0
func keyboardWillShow() {
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.Origin.y < 0 {
viewMovedUp = false
}
}
func keyboardWillHide() {
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
else if view.frame.Origin.y < 0 {
viewMovedUp = false
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if sender.isEqual(mailTf) {
//move the main view, so that the keyboard does not hide it.
if view.frame.Origin.y >= 0 {
viewMovedUp = true
}
}
}
func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
// if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {
rect.Origin.y -= keyBoardSize
rect.size.height += keyBoardSize
}
else {
// revert back to the normal state.
rect.Origin.y += keyBoardSize
rect.size.height -= keyBoardSize
}
view.frame = rect
UIView.commitAnimations()
}
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}
func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
dans (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
if (textField.frame.Origin.y > self.view.frame.size.height - 216)
{
if (screenHeight>500)
scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
else
scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.Origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
[scrollView setContentOffset:scrollPoint animated:YES];
}
[scrollView setScrollEnabled:YES];
lors de la démission de KeyBoard, vous devez écrire du code ci-dessous.
scrollView.contentSize = CGSizeMake(0.0, 640);
CGPoint scrollPoint = CGPointMake(0.0,0.0);
[scrollView setContentOffset:scrollPoint animated:YES];
Pour Swift Developer, à l'aide de Swift 3, voici le rapport https://github.com/jamesrochabrun/KeyboardWillShow
import UIKit
class ViewController: UIViewController {
//1 Create a view that will hold your TEXTFIELD
let textField: UITextField = {
let tf = UITextField()
tf.translatesAutoresizingMaskIntoConstraints = false
tf.layer.borderColor = UIColor.darkGray.cgColor
tf.layer.borderWidth = 3.0
return tf
}()
//2 global variable that will hold the bottom constraint on changes
var textfieldBottomAnchor: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
//3 add the view to your controller
view.addSubview(textField)
textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
textfieldBottomAnchor?.isActive = true
setUpKeyBoardObservers()
}
//4 Use NSnotificationCenter to monitor the keyboard updates
func setUpKeyBoardObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
//5 toggle the bottom layout global variable based on the keyboard's height
func handleKeyboardWillShow(notification: NSNotification) {
let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
if let keyboardFrame = keyboardFrame {
textfieldBottomAnchor?.constant = -keyboardFrame.height
}
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
func handleKeyboardWillHide(notification: NSNotification) {
textfieldBottomAnchor?.constant = 0
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
if let keyboardDuration = keyboardDuration {
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
})
}
}
//6 remove the observers
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
}
Dans iOS, déplacer le clavier vers le haut et reprendre pour les champs de texte dans l'application est un peu déroutant et nécessite d'implémenter peu de méthodes pour la même chose . chaque classe où les champs de texte existent.
Je préfère utiliser ce contrôle Github.
Dans lequel Nous n'avons rien à faire. - glissez simplement le contrôle de la chute vers votre projet et construisez - Il fera tout pour votre application.
Merci
Peut-être que cela sera utile.
J'ai trouvé @DK_ comme la solution que j'ai commencé à utiliser. Cependant, on suppose que scrollView couvre la totalité de la vue. Ce n'était pas le cas pour moi. Je voulais seulement une scrollView au cas où le clavier couvrait le champ de texte inférieur de mon écran de connexion. Ainsi, la taille de mon contenu était la même que celle du défilement, qui était plus petite que la vue principale.
Cela ne tenait pas non plus compte des paysages, et c'est là que j'ai eu des problèmes pour commencer. Après avoir joué avec elle pendant plusieurs jours, voici ma méthode keyboardWasShown:
.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
// A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
CGFloat height = 0;
NSDictionary* info = [aNotification userInfo];
CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.
CGRect scrollRect = scrollView.frame;
CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);
if (!CGRectIsNull(intersect))
{
height = intersect.size.height;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
// Figure out what the view rectangle is for the scrollView
CGPoint contentOffset = scrollView.contentOffset;
CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y); // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
visibleRect.size.height -= height;
CGRect activeRect = activeField.frame;
if (!CGRectContainsRect(visibleRect, activeRect))
{
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
J'ai aussi eu quelques difficultés à travailler avec la mise en page automatique. Si les mises en page ne sont pas correctement effectuées, je ne reçois pas le défilement auquel je m'attendais. Une chose qui a rendu la vie beaucoup plus facile a été de placer tous les éléments qui devaient défiler dans une vue unique, et de le placer comme seul élément de la vue de défilement. J'ai appelé cette vue unique la "vue du contenu".
Je pense que l'essentiel était que la vue du contenu ait une largeur et une hauteur définies. Cela permettait à la vue par défilement de savoir exactement combien de contenu elle devait traiter. Cela va un peu en arrière par rapport aux mises en page habituelles. Normalement, les vues essaient de prendre le plus de place possible. Avec le contenu d'une vue de défilement, vous essayez de limiter au maximum la vue. La vue du contenu vous permet de mettre un terme à cela. J'ai donc donné au mien une hauteur de 248 et utilisé la largeur d'écran standard de 320 comme largeur.
Les dispositions qui ont finalement fonctionné pour moi étaient les suivantes:
Horizontal Space - View - Scroll View
(0)Vertical Space - View - Scroll View
(0)Horizontal Space - Scroll View - View
(0)Height - (248) - Scroll View
Vertical Space - View - Scroll View
(0)Vertical Space - Scroll View - View
(0)Horizontal Space - View - Scroll View
(0)Horizontal Space - Scroll View - View
(0)Height - (248) - View
Width - (320) - View
Vous pouvez utiliser ce simple référentiel Git: https://github.com/hackiftekhar/IQKeyboardManager
C'est une bibliothèque qui gère automatiquement tous les déplacements de champs.
Selon leur readme, l’intégration est super facile:
sans que vous ayez besoin d'entrer un code et aucune configuration supplémentaire n'est requise. Pour utiliser IQKeyboardManager, vous vous devez simplement ajouter des fichiers source à votre projet} _
Bien que ce soit un très bon contrôle, il provoque parfois des conflits, comme dans les contrôleurs de vue avec vue à défilement. Cela change parfois la taille du contenu. Néanmoins, vous pouvez y aller et l'essayer selon vos besoins, vous pourriez peut-être faire ce que j'ai manqué.
voir UICatalogView
exemples d'iphone live et chargé
j'ai eu un problème avec le retour à la vue principale par défaut lors de la modification du champ de texte ou de la modification de son contenu (par exemple, textfield téléphone et ajout du signe '-', et la vue revient à couvrir les champs de texte) modification constante des contraintes, pas de la taille ni de la position du cadre dans les fonctions de délégation de notification, comme ceci:
P.S. Je ne me sers pas de scrollview mais simplement de déplacer la vue vers le haut, mais cela devrait fonctionner
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if !keyboardIsShown{
self.infoViewTopConstraint.constant -= keyboardSize.height
self.infoViewBottomConstraint.constant += keyboardSize.height
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
keyboardIsShown = true
}
}
func keyboardWillHide(notification: NSNotification) {
if keyboardIsShown {
self.infoViewTopConstraint.constant += keyboardSize.height
self.infoViewBottomConstraint.constant -= keyboardSize.height
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
keyboardIsShown = false
}
Cette question a déjà beaucoup de réponses, certains ont dit utiliser la vue par défilement, d'autres ont dit utiliser une troisième bibliothèque.
Mais pour moi, la solution devrait être UITableViewController
avec des cellules statiques.
Vous séparez votre interface utilisateur en plusieurs parties et vous les insérez une par une dans les tablesViewCells. Plus besoin de vous soucier du clavier, tableViewController le gérera automatiquement.
Il peut être un peu difficile de calculer le remplissage, la marge, la hauteur de la cellule, mais si votre calcul est bon, c'est simple.
J'utilise Swift et la mise en page automatique (mais je ne peux pas commenter la réponse Swift précédente); voici comment je le fais sans une vue de défilement:
J'organise mon formulaire dans IB avec des contraintes verticales entre les champs pour les séparer. J'ajoute une contrainte verticale du champ le plus haut à la vue Conteneur et crée un point de vente correspondant (topSpaceForFormConstraint dans le code ci-dessous). Il suffit de mettre à jour cette contrainte, ce que je fais dans un bloc d'animation pour un mouvement doux de Nice. La vérification de la hauteur est facultative bien sûr, dans ce cas, je devais le faire uniquement pour la plus petite taille d'écran.
Ceci peut être appelé en utilisant l’une des méthodes textFieldDidBeginEditing ou keyboardWillShow habituelles.
func setFormHeight(top: CGFloat)
{
let height = UIScreen.mainScreen().bounds.size.height
// restore text input fields for iPhone 4/4s
if (height < 568) {
UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {
self.topSpaceForFormConstraint.constant = top
self.view.layoutIfNeeded()
}, completion: nil)
}
}
Je n'ai pas vu cette possibilité ici, donc je l'ajoute, car j'ai essayé les méthodes dans les réponses mais quelques heures plus tard, j'ai découvert qu'il y avait beaucoup moyen plus simple dans XCode 5 sous iOS6/7: Utilisez NSLayoutConstraints.
Voir: contrainte autolayout - clavier
Voici mon code:
fichier .m:
// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
NSLog(@"keyboardWillBeShown:");
[self.PhoneNumberLabelOutlet setHidden:TRUE];
CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
thisConstraint.constant -= heightOfLabel;
}
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat oldConstant = [self.SignInYConstraint constant];
self.SignInYConstraint.constant = oldConstant + kbSize.height;
[self.view setNeedsUpdateConstraints];
NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
[self.view layoutIfNeeded];
}];
}
fichier .h:
#import <UIKit/UIKit.h>
@interface SignInViewController : UIViewController {
UITextField* _activeField;
}
- (void)signInCallback:(NSObject*)object;
@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;
@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;
@property (weak, nonatomic) IBOutlet UIButton *SignInButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;
@end
Swift 5
dans viewDidLoad ou viewDidAppear, la méthode add addKeyboardObservers.
fileprivate func addKeyboardObservers(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
fileprivate func removeKeyboardObservers(){
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}
@objc fileprivate func keyboardWillHide(_ notification: Notification){
if (window == nil) {return}
guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = .zero
}
@objc fileprivate func keyboardWillShow(_ notification: Notification){
if (window == nil) {return}
if UIApplication.shared.applicationState != .active { return }
// keyboard height
guard let height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height else {return}
// keyboard present animation duration
guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}
scrollView.contentInset.bottom = height
}
n'oubliez pas de retirer les observateurs de deinit ou de les faire disparaître
self.removeKeyboardObservers()
je suis un peu en retard. Vous devez ajouter scrollView sur votre viewController.
Vous devez être implémenté ci-dessous 2 méthode.
Méthode de délégué TextField.
- (void)textFieldDidBeginEditing:(UIView *)textField {
[self scrollViewForTextField:reEnterPINTextField];
}
Et ensuite, appelez le methon ci-dessous dans la méthode déléguée.
- (void)scrollViewForTextField:(UIView *)textField {
NSInteger keyboardHeight = KEYBOARD_HEIGHT;
if ([textField UITextField.class]) {
keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
}
CGRect screenFrame = [UIScreen mainScreen].bounds;
CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
aRect.size.height -= keyboardHeight;
CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);
if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
[contentSlidingView setContentOffset:scrollPoint animated:YES];
}
}
Ajouter mes 5 cent :)
Je préfère toujours utiliser tableView pour inputTextField ou scrollView. En combinaison avec Notifications, vous pouvez facilement gérer un tel comportement. (Remarque: si vous utilisez des cellules statiques dans tableView, un tel comportement sera automatiquement géré pour vous.)
// MARK: - Notifications
fileprivate func registerNotificaitions() {
NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillAppear(_:)),
name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillDisappear),
name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func unregisterNotifications() {
NotificationCenter.default.removeObserver(self)
}
@objc fileprivate func keyboardWillAppear(_ notification: Notification) {
if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.3, animations: {
let heightInset = keyboardHeight - self.addDeviceButton.frame.height
self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightInset, right: 0)
self.view.layoutIfNeeded()
}, completion: nil)
}
}
@objc fileprivate func keyboardWillDisappear() {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.3, animations: {
self.tableView.contentInset = UIEdgeInsets.zero
self.view.layoutIfNeeded()
}, completion: nil)
}