Tôi cần kiểm tra tình trạng hiển thị bàn phím trong ứng dụng iOS của mình.
Mã giả:
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
Làm thế nào tôi có thể kiểm tra tình trạng này?
Tôi cần kiểm tra tình trạng hiển thị bàn phím trong ứng dụng iOS của mình.
Mã giả:
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
Làm thế nào tôi có thể kiểm tra tình trạng này?
Câu trả lời:
… Hoặc làm theo cách dễ dàng:
Khi bạn nhập một Trường văn bản, Trường này sẽ trở thành phản hồi đầu tiên và bàn phím sẽ xuất hiện. Bạn có thể kiểm tra trạng thái của bàn phím với [myTextField isFirstResponder]
. Nếu nó trả về YES
, thì bàn phím đang hoạt động.
Mã của drawnonward rất gần, nhưng va chạm với không gian tên của UIKit và có thể dễ sử dụng hơn.
@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
+load
là một phương thức đặc biệt được gọi bởi Objective-C runtime. Nó được gọi cho mỗi lớp sau khi tải nhị phân ứng dụng, nhưng trước khi main()
hàm được nhập. Không có gì đảm bảo rằng một nhóm tự động vui lòng sẽ hoạt động.
NSAutoreleasePool
alloc
/ release
bây giờ có thể được thay thế bằng cách bao quanh mã trong@autoreleasepool { }
Tạo UIKeyboardListener
khi bạn biết bàn phím không hiển thị, chẳng hạn như bằng cách gọi [UIKeyboardListener shared]
từ 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
+(void)load
để gọi init trên lớp nghe này để nói chung nó sẽ hoạt động dưới dạng kéo và thả vào bất kỳ dự án nào và khởi tạo từ lần khởi chạy ứng dụng thứ hai thay vì bạn phải nhớ init nó ở bất kỳ đâu.
Tôi nghĩ bạn cần sử dụng các thông báo được cung cấp về bàn phím:
Thông báo bàn phím
Khi hệ thống hiển thị hoặc ẩn bàn phím, nó sẽ đăng một số thông báo về bàn phím. Các thông báo này chứa thông tin về bàn phím, bao gồm cả kích thước của bàn phím, mà bạn có thể sử dụng để tính toán liên quan đến các chế độ xem di chuyển. Đăng ký các thông báo này là cách duy nhất để nhận một số loại thông tin về bàn phím. Hệ thống gửi các thông báo sau cho các sự kiện liên quan đến bàn phím:
* UIKeyboardWillShowNotification * UIKeyboardDidShowNotification * UIKeyboardWillHideNotification * UIKeyboardDidHideNotification
Để biết thêm thông tin về các thông báo này, hãy xem mô tả của chúng trong Tài liệu tham khảo Lớp UIWindow. Để biết thông tin về cách hiển thị và ẩn bàn phím, hãy xem Văn bản và Web.
Triển khai 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
}
}
Sử dụng hệ thống phân cấp chế độ xem phụ cửa sổ làm dấu hiệu cho việc hiển thị bàn phím là một hành vi hack. Nếu Apple thay đổi cách triển khai cơ bản của họ, tất cả những câu trả lời này sẽ bị phá vỡ.
Cách đúng sẽ là theo dõi ứng dụng hiển thị Bàn phím và ẩn thông báo, chẳng hạn như bên trong Đại biểu ứng dụng của bạn:
Trong AppDelegate.h:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (assign, nonatomic) BOOL keyboardIsShowing;
@end
Trong 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;
}
Sau đó, bạn có thể kiểm tra bằng cách sử dụng:
BOOL keyboardIsShowing = ((AppDelegate*)[UIApplication sharedApplication].delegate).keyboardIsShowing;
Cần lưu ý rằng các thông báo hiển thị / ẩn bàn phím sẽ không kích hoạt khi người dùng đang sử dụng bluetooth hoặc bàn phím ngoài.
Thêm phần mở rộng
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
}
}
}
Sau đó, kiểm tra xem có bàn phím hay không,
if UIApplication.shared.isKeyboardPresented {
print("Keyboard presented")
} else {
print("Keyboard is not presented")
}
guard let keyboardWindowClass = NSClassFromString("UIRemoteKeyboardWindow") else { return false }; return UIApplication.shared.windows.contains(where: { $0.isKind(of: keyboardWindowClass) })
Đây là từ Hướng dẫn lập trình văn bản trên iOS do Apple xuất bản tại đây: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Về cơ bản, hãy gọi "registerForKeyBoardNotifications" trong ViewDidLoad của bạn. Sau đó, mỗi khi bàn phím hoạt động, "keyboardWasShown" sẽ được gọi. Và mỗi khi bàn phím biến mất, "keyboardWillBeHidden" được gọi.
// 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;
}
Bây giờ trong iOS8 giải pháp này tất nhiên không hoạt động. Ban đầu nó được viết cho IOS4 / 5.
Hãy thử giải pháp này:
- (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;
}
Một vài nhận xét:
Mẫu đề xuất cho một đối tượng singleton sẽ như sau. disp_once đảm bảo rằng lớp được khởi tạo một lần theo cách an toàn cho luồng và biến tĩnh không hiển thị bên ngoài. Và đó là GCD tiêu chuẩn, vì vậy không cần biết về các chi tiết cấp thấp của Objective-C.
+ (KeyboardStateListener *)sharedInstance
{
static KeyboardStateListener* shared;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [[KeyboardStateListener alloc] init];
// Other initialisations
});
return shared;
}
Thông thường, bạn không muốn chỉ biết bàn phím có hiển thị hay không, mà là nó lớn như thế nào. Không phải tất cả các bàn phím đều có cùng kích thước. Bàn phím iPhone nhỏ hơn bàn phím iPad. Vì vậy, bạn muốn có một thuộc tính khác @property (readonly, nonatomic) CGRect keyboardRect;
được đặt trong phương thức notificationShowKeyboard: như sau:
NSValue* value = notification.userInfo [UIKeyboardFrameEndUserInfoKey];
_keyboardRect = value.CGRectValue;
Điều quan trọng cần lưu ý là hình chữ nhật nằm trong tọa độ UIWindow và không tôn trọng việc xoay màn hình. Vì vậy, người gọi sẽ chuyển đổi hình chữ nhật đó bằng cách gọi
KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];
Nếu người dùng xoay màn hình trong khi bàn phím hiển thị, ứng dụng sẽ được thông báo rằng bàn phím bị ẩn, sau đó hiển thị lại. Khi nó được hiển thị, các chế độ xem khác rất có thể vẫn chưa được xoay. Vì vậy, nếu bạn tự quan sát các sự kiện ẩn / hiện trên bàn phím, hãy chuyển đổi tọa độ khi bạn thực sự cần chúng, không phải trong thông báo.
Nếu người dùng tách hoặc tháo bàn phím hoặc sử dụng bàn phím phần cứng, các thông báo sẽ luôn hiển thị bàn phím ở dạng ẩn. Hủy bỏ hoặc hợp nhất bàn phím sẽ gửi thông báo "bàn phím được hiển thị".
Người nghe phải được khởi tạo trong khi bàn phím bị ẩn, nếu không, thông báo đầu tiên sẽ bị bỏ qua và người ta sẽ cho rằng bàn phím bị ẩn khi không có.
Vì vậy, nó là khá quan trọng để biết những gì bạn thực sự muốn. Mã này rất hữu ích để di chuyển mọi thứ ra khỏi bàn phím (với bàn phím tách hoặc không gắn, đó là trách nhiệm của người dùng). Nó không cho bạn biết liệu người dùng có thể nhìn thấy bàn phím trên màn hình hay không (trong trường hợp bàn phím bị chia đôi). Nó không cho bạn biết liệu người dùng có thể gõ hay không (ví dụ: khi có bàn phím phần cứng). Nhìn vào các cửa sổ khác sẽ không hoạt động nếu ứng dụng tự tạo các cửa sổ khác.
Swift thực hiện:
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
}
}
Bởi vì swift không thực thi phương thức tải lớp khi khởi động, điều quan trọng là phải khởi động dịch vụ này khi khởi chạy ứng dụng:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
{
...
KeyboardStateListener.shared.start()
}
Đây là giải pháp của tôi, nó gói gọn mọi thứ vào một phương thức tĩnh duy nhất và bạn có thể gọi nó ở bất cứ đâu để kiểm tra:
+(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;
}
Và đây là cách thực hiện điều đó trong 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");
}
Đừng quên hủy đăng ký:
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardDidShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardWillHideNotification,
object: nil)
}
Và nếu bạn muốn loại bỏ bàn phím khi nhấn nút "Quay lại":
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;
}
}
Hãy thử chức năng này
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;
}
BOOL isTxtOpen = [txtfieldObjct isFirstReponder]. Nếu nó trả về YES, thì bàn phím đang hoạt động.
Để kiểm tra bàn phím thời tiết có xuất hiện hay không, chúng ta có thể sử dụng Bàn phím thông báo xác định trước.
UIKeyboardDidShowNotification, UIKeyboardDidHideNotification
Ví dụ: tôi có thể sử dụng mã sau để nghe thông báo bàn phím
// Nghe bàn phím xuất hiện và biến mất
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
trong các phương pháp tôi có thể nhận thông báo
- (void)keyboardDidShow: (NSNotification *) notifyKeyBoardShow{
// key board is closed
}
- (void)keyboardDidHide: (NSNotification *) notifyKeyBoardHide{
// key board is opened
}
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
}
}
}
Bạn có thể kiểm tra lặp đi lặp lại tất cả các lần xem văn bản, trường văn bản và nhãn trong các lần xem phụ của chế độ xem chính để xem có ai là người phản hồi đầu tiên với một cái gì đó như thế này không:
-(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;
}
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
}
}
Tôi nghĩ điều này có thể giúp bạn,
+(BOOL)isKeyBoardInDisplay {
BOOL isExists = NO;
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
if ([[keyboardWindow description] hasPrefix:@"<UITextEffectsWindow"] == YES) {
isExists = YES;
}
}
return isExists;
}
cảm ơn,
Naveen Shan