iOS 앱에서 키보드 가시성 상태를 확인해야합니다.
의사 코드 :
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
이 상태를 어떻게 확인할 수 있습니까?
iOS 앱에서 키보드 가시성 상태를 확인해야합니다.
의사 코드 :
if(keyboardIsPresentOnWindow) {
//Do action 1
}
else if (keyboardIsNotPresentOnWindow) {
//Do action 2
}
이 상태를 어떻게 확인할 수 있습니까?
답변:
… 또는 쉬운 방법을 선택하십시오.
textField를 입력하면 첫 번째 응답자가 되고 키보드가 나타납니다. 로 키보드의 상태를 확인할 수 있습니다 [myTextField isFirstResponder]
. 를 반환 YES
하면 키보드가 활성화 된 것입니다.
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
+load
Objective-C 런타임에 의해 호출되는 특수 메서드입니다. 앱 바이너리가로드 된 후 main()
함수가 입력 되기 전에 각 클래스에 대해 호출됩니다 . 자동 릴리스 풀이 라이브라는 보장은 없습니다.
NSAutoreleasePool
alloc
/는 release
지금의 코드를 주위로 대체 될 수있다@autoreleasepool { }
만들기 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
+(void)load
하여이 리스너 클래스에서 init를 호출하여 일반적으로 프로젝트에 드래그 앤 드롭으로 작동하고 어디서든 초기화해야한다는 것을 기억할 필요없이 두 번째 앱 시작부터 초기화 할 수 있습니다.
키보드에 대해 제공되는 알림을 사용해야한다고 생각합니다.
키보드 알림
시스템이 키보드를 표시하거나 숨기면 여러 키보드 알림을 게시합니다. 이러한 알림에는보기 이동과 관련된 계산에 사용할 수있는 키보드 크기 등의 정보가 포함됩니다. 이러한 알림을 등록하는 것은 키보드에 대한 일부 유형의 정보를 얻을 수있는 유일한 방법입니다. 시스템은 키보드 관련 이벤트에 대해 다음 알림을 제공합니다.
* UIKeyboardWillShowNotification * UIKeyboardDidShowNotification * UIKeyboardWillHideNotification * UIKeyboardDidHideNotification
이러한 알림에 대한 자세한 내용은 UIWindow Class Reference에서 해당 설명을 참조하십시오. 키보드를 표시하고 숨기는 방법에 대한 정보는 텍스트 및 웹을 참조하십시오.
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
}
}
키보드 표시에 대한 표시로 창 하위보기 계층 구조를 사용하는 것은 해킹입니다. 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;
사용자가 블루투스 또는 외부 키보드를 사용하는 경우 키보드 표시 / 숨기기 알림이 실행되지 않습니다.
확장 추가
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")
}
guard let keyboardWindowClass = NSClassFromString("UIRemoteKeyboardWindow") else { return false }; return UIApplication.shared.windows.contains(where: { $0.isKind(of: keyboardWindowClass) })
이것은 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;
}
이제 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;
}
몇 가지 관찰 :
싱글 톤 객체에 권장되는 패턴은 다음과 같습니다. 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];
키보드가 표시된 상태에서 사용자가 화면을 회전하면 앱에 키보드가 숨겨져 있다는 메시지가 표시되고 다시 표시됩니다. 표시 될 때 다른 뷰는 아직 회전되지 않았을 가능성이 높습니다. 따라서 키보드 숨기기 / 표시 이벤트를 직접 관찰하는 경우 알림이 아닌 실제로 필요할 때 좌표를 변환하십시오.
사용자가 키보드를 분리 또는 도킹 해제하거나 하드웨어 키보드를 사용하는 경우 알림은 항상 키보드를 숨김으로 표시합니다. 키보드를 분리하거나 병합하면 "키보드 표시"알림이 전송됩니다.
리스너는 키보드가 숨겨져있는 동안 초기화되어야합니다. 그렇지 않으면 첫 번째 알림이 누락되고 그렇지 않은 경우 키보드가 숨겨져있는 것으로 간주됩니다.
따라서 실제로 원하는 것이 무엇인지 아는 것이 매우 중요합니다. 이 코드는 키보드에서 물건을 이동하는 데 유용합니다 (분할되거나 도킹되지 않은 키보드의 경우 사용자 책임 임). 사용자가 화면에서 키보드를 볼 수 있는지 여부는 알려주지 않습니다 (분할 키보드의 경우). 사용자가 입력 할 수 있는지 여부를 알려주지 않습니다 (예 : 하드웨어 키보드가있는 경우). 앱이 다른 창을 직접 생성하면 다른 창을 볼 수 없습니다.
신속한 구현 :
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()
}
이것은 내 솔루션이며 모든 것을 단일 정적 메서드로 캡슐화하며 어디에서나 호출하여 확인할 수 있습니다.
+(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;
}
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)
}
"Return"버튼을 눌러 키보드를 닫으려면 다음을 수행하십시오.
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;
}
}
이 기능을 사용해보십시오
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;
}
날씨 키보드가 나타나는지 확인하기 위해 키보드 사전 정의 알림을 사용할 수 있습니다.
UIKeyboardDidShowNotification, UIKeyboardDidHideNotification
예를 들어 다음 코드를 사용하여 키보드 알림을 수신 할 수 있습니다.
// 키보드 모양과 사라지는 소리 듣기
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
알림을받을 수있는 방법
- (void)keyboardDidShow: (NSNotification *) notifyKeyBoardShow{
// key board is closed
}
- (void)keyboardDidHide: (NSNotification *) notifyKeyBoardHide{
// key board is opened
}
스위프트 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
}
}
}
상위 뷰의 하위 뷰에서 모든 텍스트 뷰, 텍스트 필드 및 레이블을 반복적으로 확인하여 다음과 같은 첫 번째 응답자가 있는지 확인할 수 있습니다.
-(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
}
}
이게 도움이 될 것 같아요
+(BOOL)isKeyBoardInDisplay {
BOOL isExists = NO;
for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
if ([[keyboardWindow description] hasPrefix:@"<UITextEffectsWindow"] == YES) {
isExists = YES;
}
}
return isExists;
}
감사,
나빈 샨