web-dev-qa-db-fra.com

couvertures de clavier iPhone UITextField

J'ai une application où, dans Interface Builder , j'ai configuré une UIView qui comporte un champ de texte au bas de la vue. Lorsque j'exécute l'application et que j'essaie de saisir du texte dans ce champ, le clavier se glisse le long du champ, de sorte que je ne peux pas voir ce que je tape tant que je n'ai plus caché le clavier. 

Quelqu'un d’autre a-t-il rencontré ce problème et a-t-il trouvé un bon moyen de le résoudre sans faire en sorte que la vue parent puisse défiler ou pour déplacer le champ de texte plus haut sur l’écran?

119
Cruinh

La solution habituelle est de faire glisser le champ (et tout ce qui se trouve au-dessus) avec une animation, puis de revenir en arrière lorsque vous avez terminé. Vous devrez peut-être placer le champ de texte et certains des autres éléments dans une autre vue et faire glisser la vue en tant qu'unité. (J'appelle ces choses "plaques" comme dans "plaques tectoniques", mais ce n'est que moi). Mais voici l’idée générale si vous n’avez pas besoin d’avoir envie.

- (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];
}
290
Amagrammer

Cela a fonctionné à merveille pour moi Uitextfields glissant

En particulier, il présente l'avantage de calculer la distance d'animation des diapositives en fonction de la position du champ de texte.

38
cidered

IQKeyboardManager faites ceci pour vous avec NO LINE OF CODE, il suffit de faire glisser le fichier source associé vers le projet. IQKeyboardManager prend également en charge Orientation du périphérique, Gestion automatique UIToolbar, keyboardDistanceFromTextField et bien plus que vous ne le pensez.

enter image description here

Voici l'organigramme de contrôle: Control Flow Chart

Step1: - Ajout de notifications globales de UITextField, UITextView et UIKeyboard dans une classe singleton. Je l'ai appelé IQKeyboardManager .

Step2: - Si vous avez trouvé des notifications UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification ou UITextViewTextDidBeginEditingNotification, essayez de récupérer l'instance topMostViewController à partir de la hiérarchie UIWindow.rootViewController. Afin de découvrir correctement la variable UITextFieldUITextView, le cadre de topMostViewController.view doit être ajusté.

_/Etape 3: - Distance de déplacement estimée de topMostViewController.view par rapport à la première réponse UITextFieldUITextView.

_/Etape 4: - Déplacé topMostViewController.view.frame haut/bas en fonction de la distance de déplacement attendue.

Step5: - Si vous trouvez UIKeyboardWillHideNotification, UITextFieldTextDidEndEditingNotification ou UITextViewTextDidEndEditingNotification notification, essayez à nouveau d'obtenir l'occurrence topMostViewController à partir de la hiérarchie UIWindow.rootViewController.

Step6: - Distance perturbée calculée de topMostViewController.view qui doit être restaurée à sa position d'origine.

Step7: - Restaurez topMostViewController.view.frame vers le bas en fonction de la distance perturbée.

Step8: - Singleton instancié IQKeyboardManager instance de classe lors du chargement de l'application, de sorte que chaque UITextField/UITextView de l'application s'ajuste automatiquement en fonction de la distance de déplacement prévue.

C'est tout

28

Pour développer la réponse Amagrammer, voici un exemple de classe:

LoginViewController.h

@interface LoginViewController : UIViewController <UITextFieldDelegate> {

}

@property (nonatomic, retain) IBOutlet UITextField    *emailTextField;
@property (nonatomic, retain) IBOutlet UITextField    *passwordTextField;

Notez que nous implémentons le "UITextFieldDelegate"

LoginViewController.m

@implementation LoginViewController
@synthesize emailTextField=_emailTextField;
@synthesize passwordTextField=_passwordTextField;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //Register to receive an update when the app goes into the backround
        //It will call our "appEnteredBackground method
        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appEnteredBackground)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    }
    return self;
}


- (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];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}
//This is called when the app goes into the background.
//We must reset the responder because animations will not be saved
- (void)appEnteredBackground{
    [self.emailTextField resignFirstResponder];
    [self.passwordTextField resignFirstResponder];
}
7
stebooks

Que diriez-vous de la solution officielle: Déplacement de contenu situé sous le clavier

Le réglage de votre contenu implique généralement le redimensionnement temporaire d'un ou plusieurs vues et en les plaçant de sorte que l’objet texte reste visible. Le moyen le plus simple de gérer des objets texte avec le clavier est pour les incorporer dans un objet UIScrollView (ou une de ses sous-classes comme UITableView). Lorsque le clavier est affiché, tout ce que vous devez faire est réinitialisé la zone de contenu de la vue de défilement et faites défiler le .__ désiré. objet texte en position. Ainsi, en réponse à un UIKeyboardDidShowNotification, votre méthode de gestionnaire ferait le Suivant:

  1. Obtenez la taille du clavier.
  2. Ajustez le contenu inférieur de votre vue de défilement à l’aide du clavier la taille.
  3. Faites défiler le champ de texte cible dans la vue.
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];

   [[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(keyboardWillBeHidden:)
             name:UIKeyboardWillHideNotification object:nil];

}

// 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);
    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.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.Origin) ) {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}
7
Mars

Je suis confronté au même problème dans les cellules UITableView textField. Je résous ce problème en appliquant la méthode suivante pour écouter la notification au clavier.

Observateur pour les notifications ici:

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];

Traitez ces notifications en utilisant la fonction ci-dessous:

(void)keyboardWasShown:(NSNotification*)aNotification 
(void)keyboardWillBeHidden:(NSNotification*)aNotification 
7
Boobalan

Allez voir ça . Pas de soucis pour vous.

Cette solution est très soignée. Tout ce que vous avez à faire est d'ajouter vos champs de texte dans une UIScrollView et de changer sa classe en TPKeyboardAvoidingScollView, si vous utilisez des storyboards. La vue de défilement est étendue de manière à détecter le moment où le clavier est visible et à se déplacer au-dessus du clavier à une distance raisonnable. C'est une solution parfaite car indépendante de votre UIViewController. Tout ce qui est nécessaire est fait dans la classe susmentionnée. Merci Michael Tyson et tous.

TPKeyboardAvoiding

5
ArunaNZ

Vous trouverez ci-dessous une version rapide de la réponse d'Amagrammer. De plus, une variante utilisant l'événement UIKeyboardWillShowNotification puisque je devais connaître la taille du clavier avant de déplacer la vue.

var keyboardHeight:CGFloat = 0

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil)
}

func textFieldDidBeginEditing(textField: UITextField) {
    //keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing
    //is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height.
}

func textFieldDidEndEditing(textField: UITextField) {
    animateTextField(false)
}

func animateTextField(textFieldUp:Bool) {
    let movementDistance:CGFloat = keyboardHeight
    let movementDuration = 0.3

    let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance)

    UIView.beginAnimations("anim", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration)
    self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    UIView.commitAnimations()
}

func keyboardWillChange(notification:NSNotification) {
    let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)!
    keyboardHeight = keyboardRect.height
    animateTextField(true)
}
5
Justin Domnitz

Il y avait une grande solution à éditer des champs de texte sans masquer (lien mort maintenant, voici un lien Wayback: https://web.archive.org/web/20091123074029/http://acts-as-geek. blogspot.com/2009/11/editing-textfields-without-obscuring.html ). Il montre comment déplacer une UIView existante sur une UIScrollView et la faire défiler automatiquement lorsque le clavier apparaît.

Je l'ai mis à jour un peu pour calculer la hauteur correcte pour la UIScrollView quand il y a des contrôles (comme une UITabBar) en dessous de la UIScrollBar. Voir poster mise à jour uiview .

4
GargantuChet

Voici une solution utilisant Xcode5, iOS7:

Utilisez les blocs UITextfieldDelegate et animation.

C'est presque tout le code pour ViewController mais je voulais inclure le code de délégué pour ceux qui ne sont pas encore familiers avec le motif de délégué (comme moi). J'ai également inclus du code pour masquer le clavier lorsque vous appuyez loin de la visualisation de texte.

Vous pouvez déplacer les vues (boutons, champs de texte, etc.) aussi haut que vous le souhaitez, mais assurez-vous de les remettre en place (+100 puis -100).

@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *MyTextField;

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.MyTextField.delegate = self;

}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
      NSLog(@"text began editing");

      CGPoint MyPoint = self.MyTextField.center;

      [UIView animateWithDuration:0.3
                    animations:^{

                    self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100);
                                }];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
     NSLog(@"text ENDED editing");

     CGPoint MyPoint = self.MyTextField.center;

     [UIView animateWithDuration:0.3
                 animations:^{

     self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100);
                             }];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     [self.view endEditing:YES];
}
2
Ethan Parker

J'imagine qu'une solution consisterait à déplacer l'ensemble de votre position de vues de (x, y) à (x, y-keybaardHeight) lorsque le champ de texte est cliqué et de le remettre en place lorsque le clavier est désactivé. vient (peut-être que ce ne serait pas mauvais si vous l’animiez). 

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame=self.view.frame;
    frame.Origin=CGPointMake(x...//set point here
    self.view.frame=frame;
}
1
Daniel

En plus de la solution Amagrammer, si vous utilisez cocos2d en mode portrait, changez cette ligne:

self.view.frame = CGRectOffset(self.view.frame, 0, movement);

pour ça:

[CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0);

Si vous utilisez cocos2d en mode paysage, apportez les modifications ci-dessus et modifiez les valeurs up dans textFieldDidBeginEditing: et textFieldDidEndEditing:.

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    [self animateTextField:textField up:NO];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [self animateTextField:textField up:YES];
}
0
Iron Mike

https://github.com/ZulwiyozaPutra/Shift-Keyboard-Example J'espère que cette solution a aidé. Ils sont tous Swift 3 écrits.

//
//  ViewController.Swift
//  Shift Keyboard Example
//
//  Created by Zulwiyoza Putra on 11/23/16.
//  Copyright © 2016 Zulwiyoza Putra. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    
    //connecting textfield from storyboard
    @IBOutlet weak var textField: UITextField!
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        subscribeToKeyboardNotifications()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        self.textField.delegate = self
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        unsubscribeFromKeyboardNotifications()
    }
    
    //Hide keyboard after finished editing
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    //Setup view before keyboard appeared
    func keyboardWillAppear(_ notification:Notification) {
        view.frame.Origin.y = 0 - getKeyboardHeight(notification)
    }
    
    //Setup view before keyboard disappeared
    func keyboardWillDisappear(_ notification: Notification) {
        view.frame.Origin.y = 0
    }
    
    //Getting keyboard height
    func getKeyboardHeight(_ notification:Notification) -> CGFloat {
        let userInfo = notification.userInfo
        let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
        return keyboardSize.cgRectValue.height
    }
    
    //Subscribing to notifications to execute functions
    func subscribeToKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil)
    }
    
    //Unsubscribing from notifications
    func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
    }
    
}

0
Zulwiyoza Putra

Glissez et déposez le framework que j'utilise dans mes projets. Prend en charge le renvoi automatique lorsque vous appuyez sur en dehors d'un premier intervenant ou lorsque vous faites défiler.

GTKeyboardHelper

0
mackross

Faites simplement glisser la vue de haut en bas si nécessaire: 

- (void)textFieldDidEndEditing:(UITextField *)textField {
    self.currentTextField = nil;
    [self animateTextField: textField up: NO];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [self.currentTextField resignFirstResponder];
    return YES;
}

- (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 animateWithDuration:movementDuration animations:^{
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    }];
}

N'oubliez pas de définir self comme UITextFieldDelegate et en tant que textField delegate.

(Merci à Ammagrammer, ceci est juste une réponse plus courte en utilisant des blocs pour les animations)

0
dulgan

Je crois que sur les versions plus récentes d’iOS (6.1+, voire même plus tôt), la vue sous-jacente, du moins pour UITableView, se réduit automatiquement lorsque le clavier apparaît. Il vous suffit donc de rendre le champ de texte visible dans cette vue. Dans init:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];

puis:

- (void)keyboardWasShown:(NSNotification*)notification
{
    // Scroll the text field into view so it's not under the keyboard.
    CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView];
    [self.tableView scrollRectToVisible:rect animated:YES];
}
0
Lawrence Kesteloot

J'ai eu le même problème et j'ai trouvé GTKeyboardHelper comme une solution de facilité.

Après avoir fait glisser le cadre dans votre projet, incluez le fichier d'en-tête . Téléchargez et ouvrez l'exemple de projet, puis faites glisser l'objet "Keyboard Helper" de la section des objets de xib vers la section des objets du générateur d'interface de votre projet.

Faites glisser et déposez toutes vos vues pour devenir les enfants du "Keyboard Helper".

0
Andrei Nagy

J'ai autre chose si tu veux. Le point ici est que vous souhaitez définir le centre de votre UIView sur le champ de texte que vous modifiez. 

Avant cela, vous devez enregistrer votre INITIAL_CENTER , en tant que CGPoint , à partir de self.view.center et votre INITIAL_VIEW en tant que CGRect à partir de self.view.frame dans un propriété const.

Vous pouvez créer une méthode comme celle-ci:

- (void) centerOn: (CGRect) fieldFrame {

    // Set up the center by taking the original view center
    CGPoint center = CGPointMake(INITIAL_CENTER.x,
                             INITIAL_CENTER.y - ((fieldFrame.Origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y));


    [UIView beginAnimations:@"centerViewOnField" context:nil];
    [UIView setAnimationDuration:0.50];

    if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) {
        self.view.frame = INITIAL_VIEW;
        [self.view setCenter:INITIAL_CENTER];
    } else {
        [self.view setCenter:center];
    }


    [UIView commitAnimations];
}

Ensuite, sur votre UITextFieldDelegate , vous devez appeler centerOn: (CGRect) dans les méthodes suivantes:

textFieldDidBeginEditing: (UITextField *) avec comme paramètre le cadre du champ de texte sur lequel vous souhaitez centrer. 

Et vous devez l'appeler dans votre gestionnaire d'événements, où vous fermez votre clavier, 

textFieldDidEndEditing: (UITextField *) peut être l’un des moyens de le faire, en plaçant INITIAL_VIEW en tant que paramètre de centerOn: (CGRect) .

0
Jissay

S'il vous plaît regardez mon commentaire dans ceci:

iPhone - Le clavier cache TextField

0
Dinesh reddy K

Comment gérez-vous la situation où le clavier est en place et que le cadre a été redimensionné avec une animation et un défilement afin que le champ de texte ne soit pas couvert? il suffit de faire défiler un peu plus loin si nécessaire? Le problème, c’est de rejouer toute l’animation quand il n’est pas nécessaire. Merci

0
anders