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

时间:2009-09-29 04:31:35

标签: ios objective-c keyboard

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

伪代码:

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

我该如何检查这种情况?

21 个答案:

答案 0 :(得分:64)

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

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

答案 1 :(得分: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

答案 2 :(得分:30)

当您知道键盘不可见时创建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

答案 3 :(得分:29)

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

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

  

键盘通知

     

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

* UIKeyboardWillShowNotification
* UIKeyboardDidShowNotification
* UIKeyboardWillHideNotification
* UIKeyboardDidHideNotification
     

有关这些的更多信息   通知,请参阅他们的说明   在UIWindow类参考中。对于   有关如何显示和隐藏的信息   键盘,请参阅文本和Web。

答案 4 :(得分:11)

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

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

在AppDelegate.h中:

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (assign, nonatomic) BOOL keyboardIsShowing;

@end

在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;
}

然后你可以使用:

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

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

答案 5 :(得分:9)

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
    } 
}

答案 6 :(得分: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;
}

答案 7 :(得分: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;
}

答案 8 :(得分:4)

一些观察结果:

单例对象的推荐模式如下。 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;
}

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

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

重要的是要注意矩形在UIWindow坐标中并且不尊重屏幕旋转。因此调用者可以通过调用

来转换该矩形
KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];

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

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

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

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

答案 9 :(得分:3)

以下是在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");
}

不要忘记取消注册:

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

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

如果您想在按下“返回”按钮时关闭键盘:

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

}

答案 10 :(得分:2)

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
  } 
}

因为swift在启动时不执行类加载方法,所以在应用启动时启动此服务非常重要:

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

答案 11 :(得分:2)

这是我的解决方案,它将所有内容封装到一个静态方法中,您可以在任何地方调用它来检查:

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

答案 12 :(得分:2)

添加扩展名

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
    }
}

}

然后检查键盘是否存在

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

答案 13 :(得分:1)

尝试此功能

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;

}

来自:iOS: How to access the `UIKeyboard`?

答案 14 :(得分:1)

BOOL isTxtOpen = [txtfieldObjct isFirstReponder]。如果返回YES,则表示键盘处于活动状态。

答案 15 :(得分:1)

要查看天气键盘,我们可以使用键盘预定义通知。

UIKeyboardDidShowNotification,UIKeyboardDidHideNotification

例如,我可以使用以下代码来收听键盘通知

//听取键盘外观和失踪

return view('pages.subcategorylisting')
    ->with(compact('products'));

在方法中我可以收到通知

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

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

答案 16 :(得分:1)

快捷键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
        }
   }
}

答案 17 :(得分:1)

SwiftUI - 完整示例

import SwiftUI

struct ContentView: View {
    
    @State private var text = defaultText
    
    @State private var isKeyboardShowing = false
    
    private static let defaultText = "write something..."
    
    private var gesture = TapGesture().onEnded({_ in
        UIApplication.shared.endEditing(true)
    })
    
    var body: some View {
        
        ZStack {
            Color.black
            
            VStack(alignment: .leading) {
                TextField("placeholder", text: $text)
                    .foregroundColor(.white)
                    .padding()
                    .background(Color.green)
            }
            
            .padding()
        }
        .edgesIgnoringSafeArea(.all)
        .onChange(of: isKeyboardShowing, perform: { (isShowing) in
            if isShowing {
                if text == Self.defaultText { text = "" }
            } else {
                if text == "" { text = Self.defaultText }
            }
        })
        .simultaneousGesture(gesture)
        .onReceive(NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillShowNotification), perform: { (value) in
                        isKeyboardShowing = true
                    })
        .onReceive(NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillHideNotification), perform: { (value) in
                        isKeyboardShowing = false
                    })
    }
}

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

答案 18 :(得分:0)

您可以迭代检查父视图的子视图中的所有文本视图,文本字段和标签,以查看是否有任何第一响应者具有以下内容:

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

答案 19 :(得分:0)

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
    }
}

答案 20 :(得分:-4)

我认为这可能有助于你,

+(BOOL)isKeyBoardInDisplay  {

    BOOL isExists = NO;
    for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows])   {
        if ([[keyboardWindow description] hasPrefix:@"<UITextEffectsWindow"] == YES) {
            isExists = YES;
        }  
    }

    return isExists;
}

感谢,

Naveen Shan