web-dev-qa-db-fra.com

Comment puis-je vérifier par programme si un clavier est présent dans l'application iOS?

Je dois vérifier l'état de visibilité du clavier dans mon application iOS.

Pseudocode:

if(keyboardIsPresentOnWindow) {
    //Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
    //Do action 2
}

Comment puis-je vérifier cette condition?

101
Jitendra Singh

… Ou prenez le chemin facile:

Lorsque vous entrez un textField, il devient first responder et le clavier apparaît. Vous pouvez vérifier l’état du clavier avec [myTextField isFirstResponder]. S'il renvoie YES, le clavier est actif. 

63
thpitsch

le code de drawnonward est très proche, mais entre en conflit avec l'espace de noms d'UIKit et pourrait être rendu plus facile à utiliser.

@interface KeyboardStateListener : NSObject {
    BOOL _isVisible;
}
+ (KeyboardStateListener *)sharedInstance;
@property (nonatomic, readonly, getter=isVisible) BOOL visible;
@end

static KeyboardStateListener *sharedInstance;

@implementation KeyboardStateListener

+ (KeyboardStateListener *)sharedInstance
{
    return sharedInstance;
}

+ (void)load
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    sharedInstance = [[self alloc] init];
    [pool release];
}

- (BOOL)isVisible
{
    return _isVisible;
}

- (void)didShow
{
    _isVisible = YES;
}

- (void)didHide
{
    _isVisible = NO;
}

- (id)init
{
    if ((self = [super init])) {
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

@end
62
rpetrich

Créez un UIKeyboardListener lorsque vous savez que le clavier n'est pas visible, par exemple en appelant [UIKeyboardListener shared] à partir de applicationDidFinishLaunching.

@implementation UIKeyboardListener

+ (UIKeyboardListener) shared {
    static UIKeyboardListener sListener;    
    if ( nil == sListener ) sListener = [[UIKeyboardListener alloc] init];

    return sListener;
}

-(id) init {
    self = [super init];

    if ( self ) {
        NSNotificationCenter        *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(noticeShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(noticeHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
    }

    return self;
}

-(void) noticeShowKeyboard:(NSNotification *)inNotification {
    _visible = true;
}

-(void) noticeHideKeyboard:(NSNotification *)inNotification {
    _visible = false;
}

-(BOOL) isVisible {
    return _visible;
}

@end
29
drawnonward

Je pense que vous devez utiliser les notifications fournies sur le clavier:

De: http://developer.Apple.com/iphone/library/ documentation/UIKit/Reference/UITextField_Class/Reference/UITextField.html

Notifications du clavier

Lorsque le système affiche ou masque le clavier, il affiche plusieurs clavier notifications. Ces notifications contient des informations sur le clavier, y compris sa taille, qui vous pouvez utiliser pour les calculs que impliquer des vues en mouvement. Enregistrement pour ces notifications sont le seul moyen de obtenir des informations sur le clavier. Le système fournit le notifications suivantes pour événements liés au clavier:

* UIKeyboardWillShowNotification
* UIKeyboardDidShowNotification
* UIKeyboardWillHideNotification
* UIKeyboardDidHideNotification

Pour plus d’informations sur ces notifications, voir leurs descriptions dans UIWindow Class Reference. Pour informations sur la façon d'afficher et de masquer le clavier, voir Texte et Web.

29
beggs

Utiliser la hiérarchie de sous-vues de la fenêtre comme indication pour l'affichage au clavier est un hack. Si Apple change la mise en œuvre sous-jacente, toutes ces réponses se briseraient.

La bonne façon serait de surveiller l'affichage du clavier et de masquer les notifications au niveau de l'application, par exemple à l'intérieur de votre délégué:

Dans AppDelegate.h:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (assign, nonatomic) BOOL keyboardIsShowing;

@end

Dans AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    // Monitor keyboard status application wide
    self.keyboardIsShowing = NO;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                             name:UIKeyboardWillHideNotification object:nil];

    return YES;
}

- (void)keyboardWillShow:(NSNotification*)aNotification
{
    self.keyboardIsShowing = YES;
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.keyboardIsShowing = NO;
}

Ensuite, vous pouvez vérifier en utilisant:

BOOL keyboardIsShowing = ((AppDelegate*)[UIApplication sharedApplication].delegate).keyboardIsShowing;

Il convient de noter que les notifications d’affichage/masquage du clavier ne se déclenchent pas lorsque l’utilisateur utilise un clavier Bluetooth ou externe.

11
Vlad

Mise en œuvre de Swift 3

    import Foundation
class KeyboardStateListener: NSObject
{
    static let shared = KeyboardStateListener()
    var isVisible = false

    func start() {
        NotificationCenter.default.addObserver(self, selector: #selector(didShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(didHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    func didShow()
    {
        isVisible = true
    }

    func didHide()
    {
        isVisible = false
    } 
}
9

Ceci est tiré du Guide de programmation de texte iOS publié par Apple ici: https://developer.Apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

En gros, appelez "registerForKeyBoardNotifications" dans votre ViewDidLoad. Ensuite, chaque fois que le clavier devient actif, "keyboardWasShown" est appelé. Et chaque fois que le clavier disparaît, "keyboardWillBeHidden" est appelé.

// 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 {
    NSLog(@"Keyboard is active.");
    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 {
    NSLog(@"Keyboard is hidden");
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}
5
Scuttle

Maintenant, dans iOS8, cette solution ne fonctionne bien sûr pas… .. Elle a été écrite initialement pour IOS4/5.

Essayez cette solution:

- (BOOL) isKeyboardOnScreen 
{
    BOOL isKeyboardShown = NO;

    NSArray *windows = [UIApplication sharedApplication].windows;
    if (windows.count > 1) {
        NSArray *wSubviews =  [windows[1]  subviews];
        if (wSubviews.count) {
            CGRect keyboardFrame = [wSubviews[0] frame];
            CGRect screenFrame = [windows[1] frame];
            if (keyboardFrame.Origin.y+keyboardFrame.size.height == screenFrame.size.height) {
                isKeyboardShown = YES;
            }
        }
    }

    return isKeyboardShown;
}
5
malex

Quelques observations: 

Le modèle recommandé pour un objet singleton serait le suivant. dispatch_once s'assure que la classe est initialisée une fois de manière thread-safe et que la variable statique n'est pas visible à l'extérieur. Et c’est la norme GCD, vous n’avez donc pas besoin de connaître les détails bas niveau d’Objective-C.

+ (KeyboardStateListener *)sharedInstance
{
    static KeyboardStateListener* shared;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[KeyboardStateListener alloc] init];
        // Other initialisations
    });

    return shared;
}

Généralement, vous ne voulez pas savoir si le clavier est visible ou non, mais quelle est sa taille. Les claviers n'ont pas tous la même taille. Les claviers iPhone sont plus petits que les claviers iPad. Donc, vous voudriez une autre propriété @property (readonly, nonatomic) CGRect keyboardRect; qui est définie dans la méthode noticeShowKeyboard:

NSValue* value = notification.userInfo [UIKeyboardFrameEndUserInfoKey];
_keyboardRect = value.CGRectValue;

Important de noter que le rectangle est en coordonnées UIWindow et ne respecte pas la rotation de l'écran. Ainsi, l'appelant convertirait ce rectangle en appelant

KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];

Si l'utilisateur fait pivoter l'écran alors que le clavier est visible, l'application sera informée que le clavier est masqué, puis affiché à nouveau. Lorsqu'il est affiché, les autres vues ne sont probablement pas encore pivotées. Donc, si vous observez vous-même les événements de masquage/affichage au clavier, convertissez les coordonnées lorsque vous en avez réellement besoin, et non dans la notification. 

Si l'utilisateur divise ou libère le clavier, ou utilise un clavier matériel, les notifications indiqueront toujours que le clavier est masqué. Le désaccouplement ou la fusion du clavier enverra une notification "clavier affiché". 

L'auditeur doit être initialisé alors que le clavier est masqué, sinon la première notification sera manquée et on supposera que le clavier est masqué lorsqu'il ne l'est pas. 

Il est donc très important de savoir ce que vous voulez réellement. Ce code est utile pour déplacer des éléments hors du chemin du clavier (avec un clavier divisé ou non relié, c'est la responsabilité de l'utilisateur). Cela ne vous dit pas si l'utilisateur peut voir un clavier à l'écran (dans le cas d'un clavier divisé). Cela ne vous dit pas si l'utilisateur peut taper (par exemple, s'il existe un clavier matériel). Regarder d'autres fenêtres ne fonctionne pas si l'application crée d'autres fenêtres elle-même. 

4
Chris

Et voici comment procéder à Swift: 

 func registerForKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "keyboardWasShown:",
        name: UIKeyboardDidShowNotification,
        object: nil)

    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "keyboardWillBeHidden:",
        name: UIKeyboardWillHideNotification,
        object: nil)
}

func keyboardWasShown(notification: NSNotification) {
    println("Keyboard was shown");
}

func keyboardWillBeHidden(notification: NSNotification) {
    println("Keyboard was dismissed");
}

N'oubliez pas de vous désinscrire:

 override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self,
        name: UIKeyboardDidShowNotification,
        object: nil)

    NSNotificationCenter.defaultCenter().removeObserver(self,
        name: UIKeyboardWillHideNotification,
        object: nil)
}

Et si vous souhaitez ignorer le clavier en appuyant sur le bouton "Retour":

class ViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var yourTextField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()
    registerForKeyboardNotifications()
    yourTextField.delegate = self
}

func textFieldShouldReturn(textField: UITextField!) -> Bool {
    self.view.endEditing(true);
    return false;
}

}
3
Teodor Ciuraru

Mise en œuvre de Swift:

class KeyboardStateListener: NSObject
{
  static var shared = KeyboardStateListener()
  var isVisible = false

  func start() {
    let nc = NSNotificationCenter.defaultCenter()
    nc.addObserver(self, selector: #selector(didShow), name: UIKeyboardDidShowNotification, object: nil)
    nc.addObserver(self, selector: #selector(didHide), name: UIKeyboardDidHideNotification, object: nil)
  }

  func didShow()
  {
    isVisible = true
  }

  func didHide()
  {
    isVisible = false
  } 
}

Comme Swift n'exécute pas la méthode de classe load au démarrage, il est important de démarrer ce service au lancement de l'application:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
{
  ...    
  KeyboardStateListener.shared.start() 
}
2
Prcela

BOOL isTxtOpen = [txtfieldObjct isFirstReponder]. Si le résultat est OUI, le clavier est actif.

1
Hardik Mamtora

C'est ma solution, elle encapsule tout dans une seule méthode statique et vous pouvez l'appeler n'importe où pour vérifier:

+(BOOL)isKeyboardVisible{
    static id tokenKeyboardWillShow = nil;
    static id tokenKeyboardWillHide = nil;
    static BOOL isKbVisible = NO;
    @synchronized (self) {
        if (tokenKeyboardWillShow == nil){
            tokenKeyboardWillShow = [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
                @synchronized (self) {
                    isKbVisible = YES;
                }
            }];
        }

        if (tokenKeyboardWillHide == nil){
            tokenKeyboardWillHide = [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillHideNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
                @synchronized (self) {
                    isKbVisible = NO;
                }
            }];
        }
    }

    return isKbVisible;
}
1
pthr

Pour vérifier météo clavier est apparu, nous pouvons utiliser les notifications prédéfinies du clavier.

UIKeyboardDidShowNotification, UIKeyboardDidHideNotification

Par exemple, je peux utiliser le code suivant pour écouter la notification au clavier

// Ecoute les apparences et les disparitions au clavier

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

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidHide:)
                                             name:UIKeyboardDidHideNotification
                                           object:nil];

dans les méthodes, je peux recevoir des notifications

- (void)keyboardDidShow: (NSNotification *) notifyKeyBoardShow{
    // key board is closed
}

- (void)keyboardDidHide: (NSNotification *) notifyKeyBoardHide{
    // key board is opened
}
1
Manoj Singhal

Essayez cette fonction

BOOL UIKeyboardIsVisible(){

BOOL keyboardVisible=NO;
// Locate non-UIWindow.
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
    if (![[testWindow class] isEqual:[UIWindow class]]) {
        keyboardWindow = testWindow;
        break;
    }
}
// Locate UIKeyboard.
for (UIView *possibleKeyboard in [keyboardWindow subviews]) {
    // iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
    if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"]) {
        keyboardVisible=YES;
    }
    if ([[possibleKeyboard description] hasPrefix:@"<UIKeyboard"]) {
        keyboardVisible=YES;
        break;
    }
}
return keyboardVisible;

}

depuis: iOS: Comment accéder au `UIKeyboard`?

1
Vanguarder

Vous pouvez vérifier de manière itérative toutes les vues de texte, champs de texte et étiquettes dans les sous-vues d'une vue parent pour voir s'il en existe un qui répond en premier avec quelque chose comme:

-(BOOL)isKeyboardActiveInView:(UIView *)view {
    for (UIView *anyView in [view subviews]) {
        if ([anyView isKindOfClass:[UITextField class]]) {
            if (((UITextField *)anyView).isFirstResponder) {
                return YES;
            }
        } else if ([anyView isKindOfClass:[UILabel class]]) {
            if (((UILabel *)anyView).isFirstResponder) {
                return YES;
            }
        } else if ([anyView isKindOfClass:[UITextView class]]) {
            if (((UITextView *)anyView).isFirstResponder) {
                return YES;
            }
        } else {
            if ([self isKeyboardActiveInView:anyView]) {
                return YES;
            }
        }
    }
    return NO;
}
0
Albert Renshaw

Swift 4.2/Swift 5

class Listener {
   public static let shared = Listener()
   var isVisible = false

   // Start this listener if you want to present the toast above the keyboard.
   public func startKeyboardListener() {
      NotificationCenter.default.addObserver(self, selector: #selector(didShow), name: UIResponder.keyboardWillShowNotification, object: nil)
      NotificationCenter.default.addObserver(self, selector: #selector(didHide), name: UIResponder.keyboardWillHideNotification, object: nil)
   }

   @objc func didShow() {
     isVisible = true
   }

    @objc func didHide(){
       isVisible = false
    }
}
0
Amrit Sidhu

Ajouter une extension

extension UIApplication {   
/// Checks if view hierarchy of application contains `UIRemoteKeyboardWindow` if it does, keyboard is presented
var isKeyboardPresented: Bool {
    if let keyboardWindowClass = NSClassFromString("UIRemoteKeyboardWindow"), self.windows.contains(where: { $0.isKind(of: keyboardWindowClass) }) {
        return true
    } else {
        return false
    }
}

}

Puis vérifiez si le clavier est présent,

if UIApplication.shared.isKeyboardPresented {
     print("Keyboard presented")
} else { 
     print("Keyboard is not presented")
}
0
Kay Cee

Swift 4

extension UIViewController {
    func registerKeyboardNotifications() {
        let center = NotificationCenter.default
        center.addObserver(self, selector: #selector(keyboardWillBeShown(note:)), name: Notification.Name.UIKeyboardWillShow, object: nil)
        center.addObserver(self, selector: #selector(keyboardWillBeHidden(note:)), name: Notification.Name.UIKeyboardWillHide, object: nil)
    }

    func removeKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)

    }

    @objc
    func keyboardWillBeShown(note: Notification) {}

    @objc
    func keyboardWillBeHidden(note: Notification) {}

}

final class MyViewController: UIViewController {

    // MARK: - Properties
    var isKeyboardVisible = false

    // MARK: - Life Cycle
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        registerKeyboardNotifications()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        removeKeyboardNotifications()
    }

    // MARK: - Keyboard Handling
    override func keyboardWillBeShown(note: Notification) {
        isKeyboardVisible = true
        let userInfo = note.userInfo
        let keyboardFrame = userInfo?[UIKeyboardFrameEndUserInfoKey] as! CGRect
        let contentInset = UIEdgeInsetsMake(0.0, 0.0, keyboardFrame.height, 0.0)
        tableView.contentInset = contentInset
    }

   override func keyboardWillBeHidden(note: Notification) {
        tableView.contentInset = .zero
        isKeyboardVisible = false
   }

   // MARK: - Test
   fileprivate func test() {
        if isKeyboardVisible { // do something
        }
   }
}
0
Amber K