From b4f91a9e4a2771991cacff908fe74c0d004de9e0 Mon Sep 17 00:00:00 2001 From: "seongho.hong" Date: Tue, 27 Aug 2019 12:30:34 +0900 Subject: [PATCH 1/2] Add keyboard observer --- Sources/ToastKeyboardObserver.h | 18 +++++++++++ Sources/ToastKeyboardObserver.m | 51 +++++++++++++++++++++++++++++++ Sources/ToastWindow.swift | 5 +-- Sources/Toaster.h | 2 ++ Toaster.xcodeproj/project.pbxproj | 12 +++++++- 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 Sources/ToastKeyboardObserver.h create mode 100644 Sources/ToastKeyboardObserver.m diff --git a/Sources/ToastKeyboardObserver.h b/Sources/ToastKeyboardObserver.h new file mode 100644 index 0000000..7039689 --- /dev/null +++ b/Sources/ToastKeyboardObserver.h @@ -0,0 +1,18 @@ +// +// KeyboardObserver.h +// Toaster +// +// Created by SeongHo on 27/08/2019. +// Copyright © 2019 Suyeol Jeon. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ToastKeyboardObserver : NSObject +@property (nonatomic, assign) BOOL didKeyboardShow; ++ (instancetype)shared; +@end + +NS_ASSUME_NONNULL_END diff --git a/Sources/ToastKeyboardObserver.m b/Sources/ToastKeyboardObserver.m new file mode 100644 index 0000000..d3f5e05 --- /dev/null +++ b/Sources/ToastKeyboardObserver.m @@ -0,0 +1,51 @@ +// +// KeyboardObserver.m +// Toaster +// +// Created by SeongHo on 27/08/2019. +// Copyright © 2019 Suyeol Jeon. All rights reserved. +// + +#import "ToastKeyboardObserver.h" +#import + +@implementation ToastKeyboardObserver + ++ (void)load { + [ToastKeyboardObserver shared]; +} + ++ (instancetype)shared { + static ToastKeyboardObserver *shared = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shared = [[self alloc] init]; + }); + return shared; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(keyboardWillShow:) + name:UIKeyboardWillShowNotification + object:nil]; + [center addObserver:self + selector:@selector(keyboardDidHide:) + name:UIKeyboardDidHideNotification + object:nil]; + } + return self; +} + +- (void)keyboardWillShow:(NSNotification*)notification { + self.didKeyboardShow = YES; +} + +- (void)keyboardDidHide:(NSNotification*)notification { + self.didKeyboardShow = NO; +} + +@end diff --git a/Sources/ToastWindow.swift b/Sources/ToastWindow.swift index 0a1d970..4110b38 100644 --- a/Sources/ToastWindow.swift +++ b/Sources/ToastWindow.swift @@ -65,8 +65,6 @@ open class ToastWindow: UIWindow { /// Will not return `rootViewController` while this value is `true`. Needed for iOS 13. private var isShowing = false - private var didKeyboardShow = false - /// Returns original subviews. `ToastWindow` overrides `addSubview()` to add a subview to the /// top window instead itself. private var originalSubviews = NSPointerArray.weakObjects() @@ -169,7 +167,6 @@ open class ToastWindow: UIWindow { } @objc private func keyboardWillShow() { - didKeyboardShow = true guard let topWindow = self.topWindow(), let subviews = self.originalSubviews.allObjects as? [UIView] else { return } for subview in subviews { @@ -220,7 +217,7 @@ open class ToastWindow: UIWindow { private func topWindow() -> UIWindow? { if let window = UIApplication.shared.windows.last(where: { // https://github.com/devxoul/Toaster/issues/152 - didKeyboardShow || $0.isOpaque + ToastKeyboardObserver.shared().didKeyboardShow || $0.isOpaque }), window !== self { return window } diff --git a/Sources/Toaster.h b/Sources/Toaster.h index 6fca4cd..485c738 100644 --- a/Sources/Toaster.h +++ b/Sources/Toaster.h @@ -2,3 +2,5 @@ FOUNDATION_EXPORT double ToasterVersionNumber; FOUNDATION_EXPORT const unsigned char ToasterVersionString[]; + +#import "ToastKeyboardObserver.h" diff --git a/Toaster.xcodeproj/project.pbxproj b/Toaster.xcodeproj/project.pbxproj index 64db492..920d6a7 100644 --- a/Toaster.xcodeproj/project.pbxproj +++ b/Toaster.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 3719A73F2255991B009EAFCD /* Toaster.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 03A75E2B1BCF2066002E46C4 /* Toaster.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C06FC9D41F95A8CC00782082 /* ToasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06FC9D31F95A8CC00782082 /* ToasterTests.swift */; }; C06FC9D61F95A8CC00782082 /* Toaster.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A75E2B1BCF2066002E46C4 /* Toaster.framework */; }; + C104FC202314D92D0034B9AB /* ToastKeyboardObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C104FC212314D92D0034B9AB /* ToastKeyboardObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -104,6 +106,8 @@ C06FC9D11F95A8CC00782082 /* ToasterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ToasterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C06FC9D31F95A8CC00782082 /* ToasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToasterTests.swift; sourceTree = ""; }; C06FC9D51F95A8CC00782082 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToastKeyboardObserver.h; sourceTree = ""; }; + C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ToastKeyboardObserver.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -161,6 +165,8 @@ 0306DBA71D85D62A007AE314 /* ToastCenter.swift */, 0306DBA81D85D62A007AE314 /* ToastView.swift */, 0306DBA91D85D62A007AE314 /* ToastWindow.swift */, + C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */, + C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */, ); path = Sources; sourceTree = ""; @@ -228,6 +234,7 @@ buildActionMask = 2147483647; files = ( 0306DBAA1D85D62A007AE314 /* Toaster.h in Headers */, + C104FC202314D92D0034B9AB /* ToastKeyboardObserver.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -320,7 +327,7 @@ TargetAttributes = { 03A75E2A1BCF2066002E46C4 = { CreatedOnToolsVersion = 7.0.1; - LastSwiftMigration = 0900; + LastSwiftMigration = 1030; }; 03A75E4E1BCF20D4002E46C4 = { CreatedOnToolsVersion = 7.0.1; @@ -400,6 +407,7 @@ 0306DBAC1D85D62A007AE314 /* ToastCenter.swift in Sources */, 0306DBAE1D85D62A007AE314 /* ToastWindow.swift in Sources */, 0306DBAB1D85D62A007AE314 /* Toast.swift in Sources */, + C104FC212314D92D0034B9AB /* ToastKeyboardObserver.m in Sources */, 0306DBAD1D85D62A007AE314 /* ToastView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -603,6 +611,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -624,6 +633,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; }; name = Release; }; From 063b3804f0a54be96f37fbfb46715b8db87c7574 Mon Sep 17 00:00:00 2001 From: "seongho.hong" Date: Wed, 28 Aug 2019 14:03:30 +0900 Subject: [PATCH 2/2] Use UIApplication extension trick for observing keyboard --- Sources/KeyboardObserver.swift | 48 +++++++++++++++++++++++++++++ Sources/ToastKeyboardObserver.h | 18 ----------- Sources/ToastKeyboardObserver.m | 51 ------------------------------- Sources/ToastWindow.swift | 2 +- Sources/Toaster.h | 2 -- Sources/UIApplication+Load.swift | 22 +++++++++++++ Toaster.xcodeproj/project.pbxproj | 16 +++++----- 7 files changed, 79 insertions(+), 80 deletions(-) create mode 100644 Sources/KeyboardObserver.swift delete mode 100644 Sources/ToastKeyboardObserver.h delete mode 100644 Sources/ToastKeyboardObserver.m create mode 100644 Sources/UIApplication+Load.swift diff --git a/Sources/KeyboardObserver.swift b/Sources/KeyboardObserver.swift new file mode 100644 index 0000000..f0cd890 --- /dev/null +++ b/Sources/KeyboardObserver.swift @@ -0,0 +1,48 @@ +// +// KeyboardObserver.swift +// Toaster +// +// Created by SeongHo Hong on 28/08/2019. +// Copyright © 2019 Suyeol Jeon. All rights reserved. +// + +import UIKit + +final class KeyboardObserver { + + static let shared = KeyboardObserver() + + private(set) var didKeyboardShow: Bool = false + + init() { + #if swift(>=4.2) + let keyboardWillShowName = UIWindow.keyboardWillShowNotification + let keyboardDidHideName = UIWindow.keyboardDidHideNotification + #else + let keyboardWillShowName = NSNotification.Name.UIKeyboardWillShow + let keyboardDidHideName = NSNotification.Name.UIKeyboardDidHide + #endif + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardWillShow), + name: keyboardWillShowName, + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(keyboardDidHide), + name: keyboardDidHideName, + object: nil + ) + } + + @objc private func keyboardWillShow() { + didKeyboardShow = true + } + + @objc private func keyboardDidHide() { + didKeyboardShow = false + } + +} + diff --git a/Sources/ToastKeyboardObserver.h b/Sources/ToastKeyboardObserver.h deleted file mode 100644 index 7039689..0000000 --- a/Sources/ToastKeyboardObserver.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// KeyboardObserver.h -// Toaster -// -// Created by SeongHo on 27/08/2019. -// Copyright © 2019 Suyeol Jeon. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface ToastKeyboardObserver : NSObject -@property (nonatomic, assign) BOOL didKeyboardShow; -+ (instancetype)shared; -@end - -NS_ASSUME_NONNULL_END diff --git a/Sources/ToastKeyboardObserver.m b/Sources/ToastKeyboardObserver.m deleted file mode 100644 index d3f5e05..0000000 --- a/Sources/ToastKeyboardObserver.m +++ /dev/null @@ -1,51 +0,0 @@ -// -// KeyboardObserver.m -// Toaster -// -// Created by SeongHo on 27/08/2019. -// Copyright © 2019 Suyeol Jeon. All rights reserved. -// - -#import "ToastKeyboardObserver.h" -#import - -@implementation ToastKeyboardObserver - -+ (void)load { - [ToastKeyboardObserver shared]; -} - -+ (instancetype)shared { - static ToastKeyboardObserver *shared = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shared = [[self alloc] init]; - }); - return shared; -} - -- (instancetype)init { - self = [super init]; - if (self) { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:self - selector:@selector(keyboardWillShow:) - name:UIKeyboardWillShowNotification - object:nil]; - [center addObserver:self - selector:@selector(keyboardDidHide:) - name:UIKeyboardDidHideNotification - object:nil]; - } - return self; -} - -- (void)keyboardWillShow:(NSNotification*)notification { - self.didKeyboardShow = YES; -} - -- (void)keyboardDidHide:(NSNotification*)notification { - self.didKeyboardShow = NO; -} - -@end diff --git a/Sources/ToastWindow.swift b/Sources/ToastWindow.swift index 4110b38..c258773 100644 --- a/Sources/ToastWindow.swift +++ b/Sources/ToastWindow.swift @@ -217,7 +217,7 @@ open class ToastWindow: UIWindow { private func topWindow() -> UIWindow? { if let window = UIApplication.shared.windows.last(where: { // https://github.com/devxoul/Toaster/issues/152 - ToastKeyboardObserver.shared().didKeyboardShow || $0.isOpaque + KeyboardObserver.shared.didKeyboardShow || $0.isOpaque }), window !== self { return window } diff --git a/Sources/Toaster.h b/Sources/Toaster.h index 485c738..6fca4cd 100644 --- a/Sources/Toaster.h +++ b/Sources/Toaster.h @@ -2,5 +2,3 @@ FOUNDATION_EXPORT double ToasterVersionNumber; FOUNDATION_EXPORT const unsigned char ToasterVersionString[]; - -#import "ToastKeyboardObserver.h" diff --git a/Sources/UIApplication+Load.swift b/Sources/UIApplication+Load.swift new file mode 100644 index 0000000..cc62c13 --- /dev/null +++ b/Sources/UIApplication+Load.swift @@ -0,0 +1,22 @@ +// +// UIApplication+Load.swift +// Toaster +// +// Created by SeongHo Hong on 28/08/2019. +// Copyright © 2019 Suyeol Jeon. All rights reserved. +// + +import Foundation + +extension UIApplication { + + open override var next: UIResponder? { + UIApplication.runOnce + return super.next + } + + private static let runOnce: Void = { + _ = KeyboardObserver.shared + }() + +} diff --git a/Toaster.xcodeproj/project.pbxproj b/Toaster.xcodeproj/project.pbxproj index 920d6a7..f5086e6 100644 --- a/Toaster.xcodeproj/project.pbxproj +++ b/Toaster.xcodeproj/project.pbxproj @@ -27,8 +27,8 @@ 3719A73F2255991B009EAFCD /* Toaster.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 03A75E2B1BCF2066002E46C4 /* Toaster.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C06FC9D41F95A8CC00782082 /* ToasterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06FC9D31F95A8CC00782082 /* ToasterTests.swift */; }; C06FC9D61F95A8CC00782082 /* Toaster.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A75E2B1BCF2066002E46C4 /* Toaster.framework */; }; - C104FC202314D92D0034B9AB /* ToastKeyboardObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C104FC212314D92D0034B9AB /* ToastKeyboardObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */; }; + C1C0178D23163F5000446CED /* KeyboardObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C0178C23163F4F00446CED /* KeyboardObserver.swift */; }; + C1C017922316419900446CED /* UIApplication+Load.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C017912316419900446CED /* UIApplication+Load.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -106,8 +106,8 @@ C06FC9D11F95A8CC00782082 /* ToasterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ToasterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C06FC9D31F95A8CC00782082 /* ToasterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToasterTests.swift; sourceTree = ""; }; C06FC9D51F95A8CC00782082 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToastKeyboardObserver.h; sourceTree = ""; }; - C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ToastKeyboardObserver.m; sourceTree = ""; }; + C1C0178C23163F4F00446CED /* KeyboardObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardObserver.swift; sourceTree = ""; }; + C1C017912316419900446CED /* UIApplication+Load.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Load.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -165,8 +165,8 @@ 0306DBA71D85D62A007AE314 /* ToastCenter.swift */, 0306DBA81D85D62A007AE314 /* ToastView.swift */, 0306DBA91D85D62A007AE314 /* ToastWindow.swift */, - C104FC1E2314D92D0034B9AB /* ToastKeyboardObserver.h */, - C104FC1F2314D92D0034B9AB /* ToastKeyboardObserver.m */, + C1C0178C23163F4F00446CED /* KeyboardObserver.swift */, + C1C017912316419900446CED /* UIApplication+Load.swift */, ); path = Sources; sourceTree = ""; @@ -234,7 +234,6 @@ buildActionMask = 2147483647; files = ( 0306DBAA1D85D62A007AE314 /* Toaster.h in Headers */, - C104FC202314D92D0034B9AB /* ToastKeyboardObserver.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -406,8 +405,9 @@ files = ( 0306DBAC1D85D62A007AE314 /* ToastCenter.swift in Sources */, 0306DBAE1D85D62A007AE314 /* ToastWindow.swift in Sources */, + C1C017922316419900446CED /* UIApplication+Load.swift in Sources */, 0306DBAB1D85D62A007AE314 /* Toast.swift in Sources */, - C104FC212314D92D0034B9AB /* ToastKeyboardObserver.m in Sources */, + C1C0178D23163F5000446CED /* KeyboardObserver.swift in Sources */, 0306DBAD1D85D62A007AE314 /* ToastView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0;