如何以编程方式检查iOS应用程序中是否存在键盘?

Jit*_*ngh 108 keyboard objective-c ios

我需要检查iOS应用中键盘可见性的状况.

伪代码:

if(keyboardIsPresentOnWindow) {
    //Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
    //Do action 2
}
Run Code Online (Sandbox Code Playgroud)

我该如何检查这种情况?

thp*_*sch 64

......或采取简单的方法:

当您输入textField时,它将成为第一响应者并出现键盘.您可以使用检查键盘的状态[myTextField isFirstResponder].如果它返回YES,则键盘处于活动状态.

  • 很好的解决方案,但是如果使用硬件键盘(在iPad上并不罕见),这将不起作用. (19认同)
  • 这不能回答问题。这将告诉您文本字段是否是第一响应者。我有一个带有多个子视图控制器的视图控制器,所有子视图控制器都包含UITextFields。使用此方法,我无法从父视图控制器判断是否显示了键盘。唯一可靠的方法是使用其他答案中说明的通知方法 (4认同)

rpe*_*ich 63

drawnonward的代码非常接近,但与UIKit的命名空间相冲突,可以更容易使用.

@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
Run Code Online (Sandbox Code Playgroud)

  • `+ load`是Objective-C运行时调用的特殊方法.在应用二进制加载后,但在输入`main()`函数之前,为每个类调用它.无法保证自动释放池将处于活动状态. (18认同)
  • 为什么需要自己的游泳池? (4认同)
  • 很好的答案!我知道这已经有好几年了,但是`NSAutoreleasePool``config` /`release`现在可以通过包围`@autoreleasepool {}中的代码来代替. (3认同)
  • 不要忘记删除Observer,可能是在KeyboardStateListener的dealloc中. (3认同)

小智 32

创建一个UIKeyboardListener当你知道键盘是不可见的,例如通过调用[UIKeyboardListener shared]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
Run Code Online (Sandbox Code Playgroud)


beg*_*ggs 29

我认为您需要使用有关键盘的通知:

来自:http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITextField_Class/Reference/UITextField.html

键盘通知

当系统显示或隐藏键盘时,它会发布几个键盘通知.这些通知包含有关键盘的信息,包括其大小,您可以将其用于涉及移动视图的计算.注册这些通知是获取有关键盘的某些类型信息的唯一方法.系统为键盘相关事件提供以下通知:

* UIKeyboardWillShowNotification
* UIKeyboardDidShowNotification
* UIKeyboardWillHideNotification
* UIKeyboardDidHideNotification
Run Code Online (Sandbox Code Playgroud)

有关这些通知的详细信息,请参阅UIWindow类参考中的说明.有关如何显示和隐藏键盘的信息,请参阅文本和Web.

  • 看看NSNotificationCenter.您必须注册您感兴趣的通知.不要忘记在您的应用程序退出时取消注册. (2认同)

Chr*_*cou 12

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
    } 
}
Run Code Online (Sandbox Code Playgroud)

  • 如果这是一个单例,则使用 deinit 没有意义,因为它永远不会被 deinited (4认同)

Vla*_*lad 11

使用窗口子视图层次结构作为键盘显示的指示是一种黑客攻击.如果Apple改变他们的基础实现,所有这些答案都会破裂.

正确的方法是监控键盘显示和隐藏应用程序范围内的通知,例如在App Delegate中:

在AppDelegate.h中:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (assign, nonatomic) BOOL keyboardIsShowing;

@end
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以检查使用:

BOOL keyboardIsShowing = ((AppDelegate*)[UIApplication sharedApplication].delegate).keyboardIsShowing;
Run Code Online (Sandbox Code Playgroud)

应该注意,当用户使用蓝牙或外部键盘时,键盘显示/隐藏通知不会触发.


mal*_*lex 5

现在在iOS8中,这个解决方案当然不起作用.它最初是为IOS4/5编写的.

尝试此解决方案:

- (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;
}
Run Code Online (Sandbox Code Playgroud)

  • 假设多个窗口包含一个键盘,而键盘始终是第二个元素,则是无效的。 (2认同)

小智 5

一些观察:

单例对象的推荐模式如下。dispatch_once 确保类以线程安全的方式初始化一次,并且静态变量在外部不可见。而且它是标准的 GCD,因此无需了解 Objective-C 的底层细节。

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

    return shared;
}
Run Code Online (Sandbox Code Playgroud)

通常你不想知道键盘是否可见,而是它有多大。并非所有键盘都具有相同的尺寸。iPhone 键盘比 iPad 键盘小。因此,您需要@property (readonly, nonatomic) CGRect keyboardRect;在 noticeShowKeyboard: 方法中设置另一个属性,如下所示:

NSValue* value = notification.userInfo [UIKeyboardFrameEndUserInfoKey];
_keyboardRect = value.CGRectValue;
Run Code Online (Sandbox Code Playgroud)

重要的是要注意矩形在 UIWindow 坐标中并且不考虑屏幕旋转。所以调用者会通过调用来转换那个矩形

KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];
Run Code Online (Sandbox Code Playgroud)

如果用户在键盘可见时旋转屏幕,应用程序将被告知键盘已隐藏,然后再次显示。显示时,其他视图很可能尚未旋转。因此,如果您自己观察键盘隐藏/显示事件,请在实际需要时转换坐标,而不是在通知中。

如果用户拆分或取消键盘,或使用硬件键盘,通知将始终显示键盘为隐藏。取消对接或合并键盘将发送“显示键盘”通知。

必须在键盘隐藏时初始化侦听器,否则将错过第一个通知,并假设键盘隐藏时隐藏。

因此,了解自己真正想要什么非常重要。此代码对于将东西移出键盘很有用(对于拆分或未对接的键盘,这是用户的责任)。它不会告诉您用户是否可以在屏幕上看到键盘(在拆分键盘的情况下)。它不会告诉您用户是否可以键入(例如,当有硬件键盘时)。如果应用程序本身创建了其他窗口,则查看其他窗口不起作用。


小智 5

这是Apple发布的iOS文本编程指南:https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

基本上在ViewDidLoad中调用"registerForKeyBoardNotifications".然后每次键盘变为活动状态时,都会调用"keyboardWasShown".每次键盘消失时,都会调用"keyboardWillBeHidden".

// 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;
}
Run Code Online (Sandbox Code Playgroud)


Kay*_*Cee 5

添加扩展

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后检查是否有键盘,

if UIApplication.shared.isKeyboardPresented {
     print("Keyboard presented")
} else { 
     print("Keyboard is not presented")
}
Run Code Online (Sandbox Code Playgroud)