Saya perlu memeriksa kondisi visibilitas keyboard di aplikasi iOS saya.
Pseudocode:
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
Bagaimana cara memeriksa kondisi ini?
Saya perlu memeriksa kondisi visibilitas keyboard di aplikasi iOS saya.
Pseudocode:
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
Bagaimana cara memeriksa kondisi ini?
Jawaban:
… Atau ambil cara mudahnya:
Saat Anda memasukkan textField, itu menjadi responder pertama dan keyboard muncul. Anda dapat memeriksa status keyboard dengan [myTextField isFirstResponder]
. Jika kembali YES
, maka keyboard aktif.
kode drawonward sangat dekat, tetapi bertabrakan dengan namespace UIKit dan dapat dibuat lebih mudah untuk digunakan.
@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
adalah metode khusus yang disebut runtime Objective-C. Ini dipanggil untuk setiap kelas setelah biner aplikasi dimuat, tetapi sebelum main()
fungsi dimasukkan. Tidak ada jaminan bahwa kumpulan rilis otomatis akan ditayangkan.
NSAutoreleasePool
alloc
/ release
sekarang dapat diganti dengan mengelilingi kode di@autoreleasepool { }
Buat UIKeyboardListener
ketika Anda tahu keyboard tidak terlihat, misalnya dengan menelepon [UIKeyboardListener shared]
dari 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
untuk memanggil init pada kelas pemroses ini sehingga secara umum akan berfungsi sebagai seret-dan-lepas ke dalam proyek apa pun dan menginisialisasi dari peluncuran aplikasi kedua daripada Anda harus ingat untuk memasukkannya di mana saja.
Saya rasa Anda perlu menggunakan pemberitahuan yang disediakan tentang keyboard:
Pemberitahuan Keyboard
Saat sistem menampilkan atau menyembunyikan keyboard, beberapa notifikasi keyboard akan diposting. Pemberitahuan ini berisi informasi tentang keyboard, termasuk ukurannya, yang dapat Anda gunakan untuk penghitungan yang melibatkan tampilan bergerak. Mendaftarkan notifikasi ini adalah satu-satunya cara untuk mendapatkan beberapa jenis informasi tentang keyboard. Sistem mengirimkan pemberitahuan berikut untuk acara terkait keyboard:
* UIKeyboardWillShowNotification * UIKeyboardDidShowNotification * UIKeyboardWillHideNotification * UIKeyboardDidHideNotification
Untuk informasi lebih lanjut tentang notifikasi ini, lihat deskripsinya di Referensi Kelas UIWindow. Untuk informasi tentang cara menampilkan dan menyembunyikan keyboard, lihat Teks dan Web.
Implementasi 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
}
}
Menggunakan hierarki subview jendela sebagai indikasi untuk menampilkan keyboard adalah hack. Jika Apple mengubah implementasi yang mendasarinya, semua jawaban ini akan rusak.
Cara yang benar adalah dengan memantau tampilan Keyboard dan menyembunyikan aplikasi notifikasi secara luas seperti di dalam Delegasi Aplikasi Anda:
Di AppDelegate.h:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (assign, nonatomic) BOOL keyboardIsShowing;
@end
Di 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;
}
Kemudian Anda dapat memeriksa menggunakan:
BOOL keyboardIsShowing = ((AppDelegate*)[UIApplication sharedApplication].delegate).keyboardIsShowing;
Perlu dicatat bahwa notifikasi tampilkan / sembunyikan keyboard tidak akan menyala saat pengguna menggunakan bluetooth atau keyboard eksternal.
Tambahkan ekstensi
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
}
}
}
Kemudian periksa apakah keyboard ada,
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) })
Ini dari Panduan Pemrograman Teks iOS yang diterbitkan oleh Apple di sini: https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Pada dasarnya panggil "registerForKeyBoardNotifications" di ViewDidLoad Anda. Kemudian setiap kali keyboard menjadi aktif, "keyboardWasShown" dipanggil. Dan setiap kali keyboard menghilang, "keyboardWillBeHidden" dipanggil.
// 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;
}
Sekarang di iOS8 solusi ini tentu saja tidak berfungsi. Itu awalnya ditulis untuk IOS4 / 5.
Coba solusi ini:
- (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;
}
Beberapa pengamatan:
Pola yang direkomendasikan untuk objek tunggal adalah sebagai berikut. dispatch_once memastikan kelas diinisialisasi satu kali dengan cara yang aman bagi thread, dan variabel statis tidak terlihat di luar. Dan itu adalah GCD standar, jadi tidak perlu tahu tentang detail level rendah Objective-C.
+ (KeyboardStateListener *)sharedInstance
{
static KeyboardStateListener* shared;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [[KeyboardStateListener alloc] init];
// Other initialisations
});
return shared;
}
Biasanya Anda tidak ingin tahu hanya apakah keyboard itu terlihat atau tidak, tetapi seberapa besar ukurannya. Keyboard tidak semuanya memiliki ukuran yang sama. Papan tombol iPhone lebih kecil dari papan ketik iPad. Jadi Anda ingin properti lain @property (readonly, nonatomic) CGRect keyboardRect;
yang disetel dalam metode noticeShowKeyboard: seperti ini:
NSValue* value = notification.userInfo [UIKeyboardFrameEndUserInfoKey];
_keyboardRect = value.CGRectValue;
Penting untuk diperhatikan bahwa persegi panjang berada dalam koordinat UIWindow dan tidak memperhatikan rotasi layar. Jadi penelepon akan mengubah persegi panjang itu dengan menelepon
KeyboardStateListener* listener = [KeyboardStateListener sharedInstance];
CGRect windowRect = listener.keyboardRect;
CGRect viewRect = [myView convertRect:windowRect fromView:self.window];
Jika pengguna memutar layar saat keyboard terlihat, aplikasi akan diberi tahu bahwa keyboard tersembunyi, lalu ditampilkan lagi. Saat ditampilkan, tampilan lain kemungkinan besar belum dirotasi. Jadi, jika Anda mengamati sendiri acara sembunyikan / tampilkan keyboard, konversikan koordinat saat Anda benar-benar membutuhkannya, bukan di pemberitahuan.
Jika pengguna memisahkan atau melepaskan keyboard, atau menggunakan keyboard hardware, notifikasi akan selalu menampilkan keyboard sebagai tersembunyi. Melepas atau menggabungkan keyboard akan mengirimkan notifikasi "keyboard ditampilkan".
Pendengar harus dijalankan saat keyboard disembunyikan, jika tidak, pemberitahuan pertama akan terlewat, dan akan dianggap bahwa keyboard disembunyikan padahal tidak.
Jadi, sangatlah penting untuk mengetahui apa yang sebenarnya Anda inginkan. Kode ini berguna untuk memindahkan barang-barang keluar dari jalan keyboard (dengan keyboard yang terbelah atau tidak terkunci, itu adalah tanggung jawab pengguna). Itu tidak memberi tahu Anda apakah pengguna dapat melihat keyboard di layar (dalam kasus keyboard terpisah). Itu tidak memberi tahu Anda apakah pengguna dapat mengetik (misalnya ketika ada keyboard perangkat keras). Melihat jendela lain tidak berfungsi jika aplikasi membuat jendela lain itu sendiri.
Swift implementasi:
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
}
}
Karena swift tidak menjalankan metode pemuatan kelas saat memulai, penting untuk memulai layanan ini saat peluncuran aplikasi:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool
{
...
KeyboardStateListener.shared.start()
}
Ini adalah solusi saya, ini merangkum semuanya menjadi satu metode statis, dan Anda dapat memanggilnya di mana saja untuk memeriksanya:
+(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;
}
Dan inilah cara melakukannya di 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");
}
Jangan lupa untuk membatalkan pendaftaran:
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardDidShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardWillHideNotification,
object: nil)
}
Dan jika Anda ingin menutup keyboard saat menekan tombol "Kembali":
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;
}
}
Coba fungsi ini
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]. Jika mengembalikan YA, maka keyboard aktif.
Untuk memeriksa apakah keyboard cuaca muncul, kita dapat menggunakan pemberitahuan Keyboard yang telah ditentukan sebelumnya.
UIKeyboardDidShowNotification, UIKeyboardDidHideNotification
Misalnya saya dapat menggunakan kode berikut untuk mendengarkan notifikasi keyboard
// Dengarkan penampilan dan penghilangan keyboard
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
dalam metode saya bisa mendapatkan notifikasi
- (void)keyboardDidShow: (NSNotification *) notifyKeyBoardShow{
// key board is closed
}
- (void)keyboardDidHide: (NSNotification *) notifyKeyBoardHide{
// key board is opened
}
Cepat 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
}
}
}
Anda dapat memeriksa semua tampilan teks, bidang teks, dan label secara berulang di sub-tampilan tampilan induk untuk melihat apakah ada responden pertama dengan sesuatu seperti ini:
-(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
}
}
Saya pikir ini dapat membantu Anda,
+(BOOL)isKeyBoardInDisplay {
BOOL isExists = NO;
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
if ([[keyboardWindow description] hasPrefix:@"<UITextEffectsWindow"] == YES) {
isExists = YES;
}
}
return isExists;
}
Terima kasih,
Naveen Shan