Comment puis-je faire un UITextField déplacer vers le haut lorsque le clavier est présent - à commencer à modifier?
-
13-09-2019 - |
Question
Avec le SDK iOS:
J'ai un UIView
avec UITextField
s qui apportent un clavier. J'ai besoin pour pouvoir:
-
Permet de faire défiler le contenu du
UIScrollView
pour voir les autres champs de texte une fois que le clavier est élevé -
automatiquement "saut" (en faisant défiler vers le haut) ou le raccourcissement
Je sais que je besoin d'un UIScrollView
. Je l'ai essayé de changer la classe de mon UIView
à un UIScrollView
mais je ne suis toujours pas faire défiler les zones de texte vers le haut ou vers le bas.
Ai-je besoin à la fois un UIView
et un UIScrollView
? Doit-on aller dans l'autre?
Ce qui doit être mis en œuvre afin de faire défiler automatiquement dans le champ de texte actif?
Idéalement comme une grande partie de la configuration des composants que possible sera fait dans Interface Builder. Je voudrais écrire du code seulement pour ce qui en a besoin.
Note:. Le UIView
(ou UIScrollView
) que je travaille avec est élevé par une barre d'onglets (de UITabBar
), qui doit fonctionner normalement
Edit: J'ajoute la barre de défilement juste lorsque le clavier arrive. Même si ce n'est pas nécessaire, je me sens comme il offre une meilleure interface, car l'utilisateur peut faire défiler et modifier les zones de texte, par exemple.
Je l'ai travail où je change la taille du cadre de la UIScrollView
lorsque le clavier monte et descend. Je suis simplement en utilisant:
-(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 veut pas automatiquement « déplacer » ou centrer les champs de texte plus bas dans la zone visible, ce qui est ce que je voudrais vraiment.
La solution
-
Vous aurez seulement besoin d'un
ScrollView
si le contenu que vous avez maintenant ne correspondent pas à l'écran de l'iPhone. (Si vous ajoutez leScrollView
comme superview des composants. Juste pour faire leTextField
défiler vers le haut lorsque le clavier arrive, il est pas nécessaire.) -
Pour montrer l'
textfields
sans être caché par le clavier, la manière standard est de déplacer vers le haut / en bas de la vue ayant textfields chaque fois que le clavier est affiché.
Voici quelques exemples 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];
}
Autres conseils
Je suis aussi avoir beaucoup de problème avec une composition de UIScrollView
de multiples UITextFields
, dont un ou plusieurs d'entre eux obtiendraient obscurci par le clavier quand ils sont en cours d'édition.
Voici quelques choses à considérer si votre UIScrollView
ne défile pas correctement.
1) Assurez-vous que votre contentSize est supérieure à la taille du cadre de UIScrollView
. La façon de comprendre UIScrollViews
est que la UIScrollView
est comme une fenêtre de visualisation sur le contenu défini dans le contentSize. Alors, quand pour que le UIScrollview
pour faire défiler partout, le contentSize doit être supérieure à la UIScrollView
. Sinon, il n'y a pas de défilement nécessaire que tout défini dans le contentSize est déjà visible. BTW, par défaut = contentSize CGSizeZero
.
2) Maintenant que vous comprenez que le UIScrollView
est vraiment une fenêtre dans votre « fenêtre » « contenu », la façon de veiller à ce que le clavier ne soit pas obscurcir votre vision de UIScrollView's
serait de redimensionner la UIScrollView
de sorte que lorsque le clavier est présent, vous avez la fenêtre UIScrollView
dimensionnée pour seulement la frame.size.height de UIScrollView
d'origine moins la hauteur du clavier. Cela garantira que la fenêtre est seulement cette petite zone visible.
3) Voici les captures: Quand je suis ce que je compris implémenté je dois obtenir le CGRect
du champ de texte édité et appelez UIScrollView's
méthode scrollRecToVisible. Je mis en œuvre la méthode UITextFieldDelegate
textFieldDidBeginEditing
avec l'appel à la méthode scrollRecToVisible
. Cela en fait travaillé avec un effet secondaire étrange que le défilement serait Magnétisme la UITextField
en position. Le plus longtemps que je ne pouvais pas comprendre ce qu'il était. Ensuite, je commentais la méthode déléguée de textFieldDidBeginEditing
et tout le travail !! (???). En fin de compte, je crois que le fait UIScrollView
apporte implicitement la UITextField
en cours d'édition dans la fenêtre visible implicitement. Ma mise en œuvre de la méthode et UITextFieldDelegate
appel ultérieur à l'scrollRecToVisible
était redondant et a été la cause de l'effet étrange de côté.
Voici donc les étapes pour faire défiler correctement votre UITextField
dans un UIScrollView
en place 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;
}
- Inscrivez-vous pour les notifications de clavier à
viewDidLoad
- Désenregistrer pour les nofitications clavier à
viewDidUnload
- Assurez-vous que le
contentSize
est réglé et plus grand que votreUIScrollView
àviewDidLoad
- Réduction de la taille la
UIScrollView
lorsque le clavier est présent - revenir la
UIScrollView
lorsque le clavier va. - Utilisez un Ivar pour détecter si le clavier est déjà affiché à l'écran puisque les notifications de clavier sont envoyées chaque fois qu'un
UITextField
est tabulé même si le clavier est déjà présent pour éviter rétrécissement l'UIScrollView
quand il est déjà rétrécis
Une chose à noter est que le UIKeyboardWillShowNotification
se déclenche même lorsque le clavier est déjà sur l'écran lorsque vous onglet sur un autre UITextField
. Je me suis occupé de cela en utilisant un Ivar pour éviter le redimensionnement de la UIScrollView
lorsque le clavier est déjà à l'écran. redimensionnement par mégarde UIScrollView
lorsque le clavier est déjà là serait désastreux!
L'espoir de ce code permet d'économiser certains d'entre vous beaucoup de maux de tête.
Il est en fait le mieux juste utiliser la mise en œuvre d'Apple, comme il est prévu dans la section docs . Cependant, le code fourni est défectueux. Remplacer la partie trouvé dans keyboardWasShown:
juste en dessous des commentaires à ce qui 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 d'Apple sont les suivants:
(1) Ils calculent toujours si le point est dans le cadre de la vue, mais il est un ScrollView
, il peut déjà avoir et vous devez défiler pour tenir compte de ce décalage:
origin.y -= scrollView.contentOffset.y
(2) Ils déplacent le contentOffset par la hauteur du clavier, mais nous voulons le contraire (nous voulons changer la contentOffset
par la hauteur qui est visible à l'écran, pas ce qui est pas):
activeField.frame.origin.y-(aRect.size.height)
Dans textFieldDidBeginEditting
et textFieldDidEndEditing
appeler la fonction [self animateTextField:textField up:YES]
comme ceci:
-(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.
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) A l'aide Interface Builder
: Sélectionner toutes les TextField => Modifier => Intégrer dans => ScrollView
1b) manuellement incorporer TextFields dans UIScrollView appelé ScrollView
2) Set UITextFieldDelegate
3) Réglez chaque textField.delegate = self;
(ou des connexions en 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];
}
Solution universelle , ici était mon approche pour la mise en œuvre IQKeyboardManager .
Etape 1: - J'ai ajouté des notifications globales de UITextField
, UITextView
et UIKeyboard
dans une classe singleton. Je l'appelle IQKeyboardManager .
Etape 2: - Si les notifications trouvées UIKeyboardWillShowNotification
, UITextFieldTextDidBeginEditingNotification
ou UITextViewTextDidBeginEditingNotification
, je tente d'obtenir par exemple topMostViewController
de la hiérarchie de UIWindow.rootViewController
. Afin de découvrir correctement UITextField
/ UITextView
sur elle, le cadre de topMostViewController.view
doit être ajustée.
Etape 3: -. Je calcule la distance de déplacement prévu de topMostViewController.view
en ce qui concerne d'abord répondu UITextField
/ UITextView
Étape 4: - je me suis déplacé topMostViewController.view.frame
haut / bas selon la distance de déplacement prévu
Étape 5: -. Si UIKeyboardWillHideNotification
trouvé, UITextFieldTextDidEndEditingNotification
ou notification UITextViewTextDidEndEditingNotification
, je tente à nouveau d'obtenir par exemple topMostViewController
de la hiérarchie de UIWindow.rootViewController
Step6: -. Je calcule la distance perturbée de topMostViewController.view
qui doit être restauré à sa position d'origine
Step7: -. Je topMostViewController.view.frame
restauré en fonction de la distance perturbée
Step8: - J'instancié singleton IQKeyboardManager instance de classe sur la charge de l'application, de sorte que chaque UITextField
/ UITextView
dans l'application ajuste automatiquement en fonction de la distance de déplacement attendue.
C'est tout IQKeyboardManager faire pour vous avec NO CODE DE LIGNE vraiment !! seulement besoin de faire glisser et déposer le fichier source relié au projet. IQKeyboardManager également soutenir Orientation de l'appareil , Gestion automatique UIToolbar , KeybkeyboardDistanceFromTextField et beaucoup plus que vous le pensez.
Je l'ai mis en place un universel, laissez tomber dans UIScrollView
, UITableView
et même sous-classe UICollectionView
qui prend soin de déplacer tous les champs de texte dans ce hors du chemin du clavier.
Lorsque le clavier est sur le point d'apparaître, la sous-classe se trouve le sous-vue qui est sur le point d'être édité, et d'ajuster son cadre et le contenu de décalage pour vous assurer que vue est visible, avec une animation pour correspondre à la fenêtre contextuelle du clavier. Lorsque le clavier disparaît, il restaure sa taille avant.
Il devrait fonctionner avec toutes configuration, soit une interface UITableView
, ou un composé de vues placé manuellement.
Il y a déjà beaucoup de réponses, mais aucune des solutions ci-dessus ont tous les trucs de positionnement de fantaisie nécessaire pour un bug-free « parfait », animation rétrocompatible et sans scintillement. (Bug lors de l'animation cadre / limites et contentOffset ensemble, les orientations d'interface différentes, iPad clavier partagé, ...)
Permettez-moi de partager ma solution:
(En supposant que vous avez mis en place 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 dit « En fait, je crois que le fait UIScrollView apporte implicitement la UITextField en cours d'édition dans la fenêtre visible implicitement » Cela semble être vrai pour iOS 3.1.3, mais pas 3.2, 4.0 ou 4.1. Je devais ajouter un scrollRectToVisible explicite afin de rendre l'UITextField visible sur iOS> = 3.2.
Ce document détaille une solution à ce problème. Regardez le code source sous 'Contenu mobile qui est situé sous le clavier. Il est assez simple.
EDIT: Remarqué il y a un petit pépin dans l'exemple. Vous voudrez probablement écouter UIKeyboardWillHideNotification
au lieu de UIKeyboardDidHideNotification
. Sinon, la vue de défilement derrière du clavier sera coupée pendant toute la durée de l'animation de clôture du clavier.
Une chose à considérer est de savoir si jamais vous voulez utiliser un UITextField
lui-même. Je ne l'ai pas rencontré des applications iPhone bien conçus qui utilisent effectivement UITextFields
en dehors de UITableViewCells
.
Il sera un travail supplémentaire, mais je vous recommande de mettre en œuvre toutes les vues d'entrée de données d'une vue de table. Ajouter un UITextView
à votre UITableViewCells
.
Solution trouvée Easiest
- (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];
}
Little correctif qui fonctionne pour beaucoup 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 se déplace avec succès le champ de texte de la manière du clavier. Mais lorsque vous faites défiler vers le haut après son utilisation et rejetant le clavier, le haut a défilée sortir de la vue. Cela est vrai pour le simulateur et l'appareil. Pour lire le contenu en haut de ce point de vue, il faut recharger la vue.
est-il pas son code suivant censé ramener la vue vers le bas?
else
{
// revert back to the normal state.
rect.origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
Pour ramener à l'état d'affichage d'origine, ajouter:
-(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];
}
}
Essayez cette courte affaire.
- (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 y a tant de solutions, mais j'ai passé quelques heures avant commencer les travaux. Donc, je mets ce code ici (il suffit de coller au projet, les modifications ne doivent pas):
@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 aide quelqu'un faire effet désiré rapidement. (Xcode 4.5)
@ user271753
Pour obtenir votre vue arrière d'ajouter d'origine:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
[self setViewMovedUp:NO];
return YES;
}
Il ne nécessite pas une vue de défilement pour pouvoir déplacer le cadre de la vue. Vous pouvez modifier le cadre d'une vue viewcontroller's
de telle sorte que toute la vue se déplace juste assez pour mettre le champ de texte firstresponder au-dessus du clavier. Quand je suis tombé sur ce problème que j'ai créé une sous-classe de UIViewController
qui fait cela. Elle observe pour le clavier apparaît notification et trouve la première sous-vue répondeur et (si nécessaire), il anime la vue principale vers le haut assez juste pour que le premier répondeur est au-dessus du clavier. Lorsque le clavier se cache, il anime la vue arrière où il était.
Pour utiliser cette sous-classe que votre contrôleur de vue personnalisée une sous-classe de GMKeyboardVC et il hérite de cette fonction (juste être sûr si vous implémentez viewWillAppear
et viewWillDisappear
ils doivent appeler super). La classe est github .
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
}
}
Voici la solution hack je suis venu avec une mise en page spécifique. Cette solution est similaire à Matt Gallagher solution dans c'est fait défiler une section en vue. Je suis encore nouveau pour le développement iPhone, et je ne connais pas la façon dont fonctionnent les mises en page. Ainsi, ce hack.
Ma mise en œuvre nécessaire pour soutenir le défilement en cliquant dans un champ, et le défilement aussi lorsque l'utilisateur sélectionne à côté du clavier.
J'ai eu un UIView avec une hauteur de 775. Les contrôles sont répartis essentiellement dans des groupes de trois sur un grand espace. J'ai fini avec la mise en page suivante IB.
UIView -> UIScrollView -> [UI Components]
vient ici le hack
I régler la hauteur de UIScrollView à 500 unités plus grandes, puis la mise en page actuelle (1250). J'ai ensuite créé un tableau avec les positions absolues que je dois faire défiler, et une fonction simple pour les obtenir en fonction du nombre de Tag 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] ;
}
Maintenant, tout ce que vous devez faire est d'utiliser les deux lignes de code suivantes dans textFieldDidBeginEditing et textFieldShouldReturn (ce dernier si vous créez une navigation de champ 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 pas « faire défiler en arrière » que d'autres méthodes font. Ce ne fut pas une exigence. Encore une fois ce fut un UIView assez « grand », et je n'ai pas eu jours pour apprendre les moteurs de mise en page interne.
par les docs , comme d'iOS 3.0, la classe UITableViewController
redimensionne automatiquement et repositionne son point de vue de la table quand il y a l'édition des champs de texte en ligne. Je pense qu'il ne suffit pas de mettre le champ de texte à l'intérieur d'un UITableViewCell
comme certains l'ont indiqué.
les docs :
Un contrôleur de vue de la table prend en charge la modification en ligne des lignes d'affichage de la table; si, par exemple, les lignes ont des champs de texte intégré en mode d'édition, il défiler la ligne en cours d'édition au-dessus du clavier virtuel qui est affiché.
Ici J'ai trouvé la solution la plus simple à manipuler le clavier.
Vous devez simplement copier-coller ci-dessous un exemple de code et changer votre textfield ou d'une vue que vous souhaitez déplacer vers le haut.
Etape-1
Il suffit de copier-coller ci-dessous deux méthode 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];
}
Etape-2
enregistrer et désenregistrer Notifications clavier viewWillAppear viewWillDisappear méthodes respectivement.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self registerForKeyboardNotifications];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self deregisterFromKeyboardNotifications];
[super viewWillDisappear:animated];
}
Etape-3
Voici la partie de l'âme, Il suffit de remplacer votre textfield, et le changement hauteur combien vous voulez déplacer à l'envers.
- (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 : bien, S'il vous plaît apprécier ce type , qui a partagé cette belle snip de code, solution propre.
L'espoir que ce serait quelqu'un revêche utile là-bas.
la recherche d'un Been bon tutoriel pour les débutants sur le sujet, a trouvé le meilleur tutoriel ici .
Dans l'exemple de MIScrollView.h
au bas du tutoriel assurez-vous de mettre un espace à
@property (nonatomic, retain) id backgroundTapDelegate;
comme vous le voyez.
Lorsque UITextField
est dans un défilement UITableViewCell
doit être configuré automatiquement.
Dans le cas contraire, il est probablement à cause du code incorrect / configuration du tableview.
Par exemple quand je rechargé ma longue table avec un UITextField
en bas comme suit,
-(void) viewWillAppear:(BOOL)animated
{
[self.tableview reloadData];
}
puis mon textfield au fond a été obscurci par le clavier qui apparaît lorsque je clique à 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 ce tiers que vous n'avez pas besoin d'écrire même une ligne
https://github.com/hackiftekhar/IQKeyboardManager
Projet de téléchargement et de glisser-déposer IQKeyboardManager dans votre projet. Si vous trouvez toute question s'il vous plaît lire un document README.
Les gars vraiment le supprimer des maux de tête pour gérer le clavier ..
Merci et bonne chance!
Remarque : cette réponse suppose que votre textField est dans un ScrollView
.Je préfère traiter cela en utilisant scrollContentInset et scrollContentOffset au lieu de vous embêter avec les cadres de mon point de vue.
D'abord nous allons écouter les notifications de 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];
}
L'étape suivante est de garder une propriété qui représente le premier courant répondeur (UITextField / UITextView qui a actuellement le clavier).
Nous utilisons les méthodes de délégués pour définir cette propriété. Si vous utilisez un autre composant, vous aurez besoin quelque chose de similaire.
Notez que pour textfield nous l'avons mis en didBeginEditing et textView dans shouldBeginEditing. En effet, textViewDidBeginEditing est appelée 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;
}
Ceci est la solution en 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
}
}