From a348a3f487c8c13e10dfd0ce7119fb851882316f Mon Sep 17 00:00:00 2001 From: Suyeol Jeon Date: Thu, 4 May 2017 21:31:03 +0900 Subject: [PATCH 1/4] Add gesture recognizer to AppDelegate.window --- Sources/RxKeyboard.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Sources/RxKeyboard.swift b/Sources/RxKeyboard.swift index a1ad7c0..9803120 100644 --- a/Sources/RxKeyboard.swift +++ b/Sources/RxKeyboard.swift @@ -35,6 +35,13 @@ public class RxKeyboard: NSObject { fileprivate let disposeBag = DisposeBag() fileprivate let panRecognizer = UIPanGestureRecognizer() + fileprivate let application: UIApplication? = { + let selector = NSSelectorFromString("sharedApplication") + return UIApplication.perform(selector)?.takeRetainedValue() as? UIApplication + }() + fileprivate var gestureView: UIView? { + return self.application?.delegate?.window ?? nil + } // MARK: Initializing @@ -93,10 +100,10 @@ public class RxKeyboard: NSObject { .withLatestFrom(frameVariable.asObservable()) { ($0, $1) } .flatMap { (gestureRecognizer, frame) -> Observable in guard case .changed = gestureRecognizer.state, - let window = UIApplication.shared.windows.first, + let view = gestureRecognizer.view, frame.origin.y < UIScreen.main.bounds.height else { return .empty() } - let origin = gestureRecognizer.location(in: window) + let origin = gestureRecognizer.location(in: view) var newFrame = frame newFrame.origin.y = max(origin.y, UIScreen.main.bounds.height - frame.height) return .just(newFrame) @@ -113,7 +120,7 @@ public class RxKeyboard: NSObject { .map { _ in Void() } .startWith(Void()) // when RxKeyboard is initialized before UIApplication.window is created .subscribe(onNext: { _ in - UIApplication.shared.windows.first?.addGestureRecognizer(self.panRecognizer) + self.gestureView?.addGestureRecognizer(self.panRecognizer) }) .disposed(by: self.disposeBag) } From 8b49c75d9e6380481037ea9881dbe215f7d932b1 Mon Sep 17 00:00:00 2001 From: Suyeol Jeon Date: Thu, 4 May 2017 21:51:20 +0900 Subject: [PATCH 2/4] Add support to set gestureView manually --- Sources/RxKeyboard.swift | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Sources/RxKeyboard.swift b/Sources/RxKeyboard.swift index 9803120..d01e1d3 100644 --- a/Sources/RxKeyboard.swift +++ b/Sources/RxKeyboard.swift @@ -19,6 +19,17 @@ public class RxKeyboard: NSObject { /// Get a singleton instance. public static let instance = RxKeyboard() + /// A view that receives pan gesture. The default value is the AppDelegate's window. Set this + /// value with the root view controller's view if the target is an App Extension. + public var gestureView: UIView? { + get { return self._gestureView ?? self.application?.delegate?.window ?? nil } + set { + self._gestureView = newValue + self.panRecognizer.view?.removeGestureRecognizer(self.panRecognizer) + newValue?.addGestureRecognizer(self.panRecognizer) + } + } + /// An observable keyboard frame. public let frame: Driver @@ -35,13 +46,12 @@ public class RxKeyboard: NSObject { fileprivate let disposeBag = DisposeBag() fileprivate let panRecognizer = UIPanGestureRecognizer() + fileprivate let application: UIApplication? = { let selector = NSSelectorFromString("sharedApplication") return UIApplication.perform(selector)?.takeRetainedValue() as? UIApplication }() - fileprivate var gestureView: UIView? { - return self.application?.delegate?.window ?? nil - } + fileprivate var _gestureView: UIView? // MARK: Initializing @@ -119,7 +129,8 @@ public class RxKeyboard: NSObject { NotificationCenter.default.rx.notification(.UIApplicationDidFinishLaunching) .map { _ in Void() } .startWith(Void()) // when RxKeyboard is initialized before UIApplication.window is created - .subscribe(onNext: { _ in + .subscribe(onNext: { [weak self] _ in + guard let `self` = self else { return } self.gestureView?.addGestureRecognizer(self.panRecognizer) }) .disposed(by: self.disposeBag) From 354d5e5f1841e786257fb0c99b91f96e7a7d78fb Mon Sep 17 00:00:00 2001 From: Suyeol Jeon Date: Thu, 4 May 2017 21:55:18 +0900 Subject: [PATCH 3/4] Add App Extension example --- Example/Podfile | 2 + Example/Podfile.lock | 8 +- .../project.pbxproj | 199 +++++++++++++++++- .../Base.lproj/MainInterface.storyboard | 26 +++ Example/RxKeyboardShareExtension/Info.plist | 36 ++++ .../ShareViewController.swift | 53 +++++ RxKeyboard.xcodeproj/project.pbxproj | 2 + 7 files changed, 320 insertions(+), 6 deletions(-) create mode 100644 Example/RxKeyboardShareExtension/Base.lproj/MainInterface.storyboard create mode 100644 Example/RxKeyboardShareExtension/Info.plist create mode 100644 Example/RxKeyboardShareExtension/ShareViewController.swift diff --git a/Example/Podfile b/Example/Podfile index b17f118..78698f6 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -12,4 +12,6 @@ target 'RxKeyboardExample' do pod 'SwiftyColor' pod 'SwiftyImage' pod 'CGFloatLiteral' + + target 'RxKeyboardShareExtension' end diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 057b303..adcaa42 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -4,7 +4,7 @@ PODS: - ReusableKit (1.1.0) - RxCocoa (3.1.0): - RxSwift (~> 3.1) - - RxKeyboard (0.4.0): + - RxKeyboard (0.4.1): - RxCocoa (>= 3.0) - RxSwift (>= 3.0) - RxSwift (3.1.0) @@ -34,7 +34,7 @@ SPEC CHECKSUMS: ManualLayout: 68ac8cfa6b5f656f7a9fadec3730208b95986880 ReusableKit: 89e743a120bab0d95848bff27e481833c2768905 RxCocoa: 50d7564866da9299161e86a263ce12a0873904d8 - RxKeyboard: cf7f4463f27e580a3542127877ef9e3a71183744 + RxKeyboard: 6bd1a1e1e199d869699ed8da2307b474137ec28f RxSwift: 83ff553e7593fdfdcb2562933a64c0284dffdadc SnapKit: 12b24f569cb7c143acc9c22b9d91b23e7b1c84a2 SwiftyColor: 7fa09db14051bc5d7f539e1c4576665975225992 @@ -42,6 +42,6 @@ SPEC CHECKSUMS: Then: 8496793c8fcac95482b943909b440724c7d8d82c UITextView+Placeholder: 77680995fcdd07c3f52ec92fe1150874a2ac89ff -PODFILE CHECKSUM: 49cf5def62bcfa2dfbe0c5118a9372a4162ec992 +PODFILE CHECKSUM: 586f03c5a1d10260c3fad008f55a493a57b525a5 -COCOAPODS: 1.1.1 +COCOAPODS: 1.2.1 diff --git a/Example/RxKeyboardExample.xcodeproj/project.pbxproj b/Example/RxKeyboardExample.xcodeproj/project.pbxproj index 41bd4bc..3462010 100644 --- a/Example/RxKeyboardExample.xcodeproj/project.pbxproj +++ b/Example/RxKeyboardExample.xcodeproj/project.pbxproj @@ -15,9 +15,37 @@ 032ABB8F1E35A9F200A3A5D4 /* MessageListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032ABB841E35A9F200A3A5D4 /* MessageListViewController.swift */; }; 032ABB901E35A9F200A3A5D4 /* MessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032ABB861E35A9F200A3A5D4 /* MessageCell.swift */; }; 032ABB911E35A9F200A3A5D4 /* MessageInputBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 032ABB871E35A9F200A3A5D4 /* MessageInputBar.swift */; }; + 035A1D241EBB38BD00A4E721 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035A1D231EBB38BD00A4E721 /* ShareViewController.swift */; }; + 035A1D271EBB38BD00A4E721 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 035A1D251EBB38BD00A4E721 /* MainInterface.storyboard */; }; + 035A1D2B1EBB38BD00A4E721 /* RxKeyboardShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 035A1D211EBB38BD00A4E721 /* RxKeyboardShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; B2F98E4D127A1E3F5A712D85 /* Pods_RxKeyboardExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DB8FDC47FB67FE136E7357D /* Pods_RxKeyboardExample.framework */; }; + E358C9143F037802E8839761 /* Pods_RxKeyboardExample_RxKeyboardShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC7ADF59D115CA60D9A9FCCF /* Pods_RxKeyboardExample_RxKeyboardShareExtension.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 035A1D291EBB38BD00A4E721 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 03E8A7161E35A95B00F7A3EC /* Project object */; + proxyType = 1; + remoteGlobalIDString = 035A1D201EBB38BD00A4E721; + remoteInfo = RxKeyboardShareExtension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 03E711911EB9151800921128 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 035A1D2B1EBB38BD00A4E721 /* RxKeyboardShareExtension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 032ABB7B1E35A9F200A3A5D4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 032ABB7D1E35A9F200A3A5D4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -28,13 +56,32 @@ 032ABB861E35A9F200A3A5D4 /* MessageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCell.swift; sourceTree = ""; }; 032ABB871E35A9F200A3A5D4 /* MessageInputBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageInputBar.swift; sourceTree = ""; }; 032ABB891E35A9F200A3A5D4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 035A1D211EBB38BD00A4E721 /* RxKeyboardShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = RxKeyboardShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 035A1D231EBB38BD00A4E721 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; + 035A1D261EBB38BD00A4E721 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; + 035A1D281EBB38BD00A4E721 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 03E711821EB9151800921128 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 03E8A71E1E35A95B00F7A3EC /* RxKeyboardRxKeyboardExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxKeyboardRxKeyboardExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 07FAFF986D58BB460D5221D6 /* Pods-RxKeyboardExample-RxKeyboardTodayExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample-RxKeyboardTodayExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample-RxKeyboardTodayExtension/Pods-RxKeyboardExample-RxKeyboardTodayExtension.debug.xcconfig"; sourceTree = ""; }; + 3B72CB29C51F6F2289A4E159 /* Pods_RxKeyboardExample_RxKeyboardTodayExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxKeyboardExample_RxKeyboardTodayExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 45C2E6E8F6E3F0046BF9AE7E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample-RxKeyboardShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample-RxKeyboardShareExtension/Pods-RxKeyboardExample-RxKeyboardShareExtension.debug.xcconfig"; sourceTree = ""; }; 7DB8FDC47FB67FE136E7357D /* Pods_RxKeyboardExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxKeyboardExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B1027686BB7DB922EB0CFF9E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample-RxKeyboardShareExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample-RxKeyboardShareExtension/Pods-RxKeyboardExample-RxKeyboardShareExtension.release.xcconfig"; sourceTree = ""; }; C2DC646E6858079F25D2BFF4 /* Pods-RxKeyboardExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample/Pods-RxKeyboardExample.release.xcconfig"; sourceTree = ""; }; + CD11C08BCCF6A765443E61DC /* Pods-RxKeyboardExample-RxKeyboardTodayExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample-RxKeyboardTodayExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample-RxKeyboardTodayExtension/Pods-RxKeyboardExample-RxKeyboardTodayExtension.release.xcconfig"; sourceTree = ""; }; + FC7ADF59D115CA60D9A9FCCF /* Pods_RxKeyboardExample_RxKeyboardShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxKeyboardExample_RxKeyboardShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FF066ACB76646CE5837B517B /* Pods-RxKeyboardExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxKeyboardExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxKeyboardExample/Pods-RxKeyboardExample.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 035A1D1E1EBB38BD00A4E721 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E358C9143F037802E8839761 /* Pods_RxKeyboardExample_RxKeyboardShareExtension.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 03E8A71B1E35A95B00F7A3EC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -100,12 +147,23 @@ path = "Supporting Files"; sourceTree = ""; }; + 035A1D221EBB38BD00A4E721 /* RxKeyboardShareExtension */ = { + isa = PBXGroup; + children = ( + 035A1D231EBB38BD00A4E721 /* ShareViewController.swift */, + 035A1D251EBB38BD00A4E721 /* MainInterface.storyboard */, + 035A1D281EBB38BD00A4E721 /* Info.plist */, + ); + path = RxKeyboardShareExtension; + sourceTree = ""; + }; 03E8A7151E35A95B00F7A3EC = { isa = PBXGroup; children = ( 032ABB7E1E35A9F200A3A5D4 /* Sources */, 032ABB881E35A9F200A3A5D4 /* Supporting Files */, 032ABB7A1E35A9F200A3A5D4 /* Resources */, + 035A1D221EBB38BD00A4E721 /* RxKeyboardShareExtension */, 03E8A71F1E35A95B00F7A3EC /* Products */, A5BB4D314040F3C02A825487 /* Pods */, 88C32DB01AFB62C918A6B8F0 /* Frameworks */, @@ -116,6 +174,7 @@ isa = PBXGroup; children = ( 03E8A71E1E35A95B00F7A3EC /* RxKeyboardRxKeyboardExample.app */, + 035A1D211EBB38BD00A4E721 /* RxKeyboardShareExtension.appex */, ); name = Products; sourceTree = ""; @@ -124,6 +183,9 @@ isa = PBXGroup; children = ( 7DB8FDC47FB67FE136E7357D /* Pods_RxKeyboardExample.framework */, + 03E711821EB9151800921128 /* NotificationCenter.framework */, + 3B72CB29C51F6F2289A4E159 /* Pods_RxKeyboardExample_RxKeyboardTodayExtension.framework */, + FC7ADF59D115CA60D9A9FCCF /* Pods_RxKeyboardExample_RxKeyboardShareExtension.framework */, ); name = Frameworks; sourceTree = ""; @@ -133,6 +195,10 @@ children = ( FF066ACB76646CE5837B517B /* Pods-RxKeyboardExample.debug.xcconfig */, C2DC646E6858079F25D2BFF4 /* Pods-RxKeyboardExample.release.xcconfig */, + 07FAFF986D58BB460D5221D6 /* Pods-RxKeyboardExample-RxKeyboardTodayExtension.debug.xcconfig */, + CD11C08BCCF6A765443E61DC /* Pods-RxKeyboardExample-RxKeyboardTodayExtension.release.xcconfig */, + 45C2E6E8F6E3F0046BF9AE7E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.debug.xcconfig */, + B1027686BB7DB922EB0CFF9E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -140,6 +206,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 035A1D201EBB38BD00A4E721 /* RxKeyboardShareExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 035A1D2E1EBB38BD00A4E721 /* Build configuration list for PBXNativeTarget "RxKeyboardShareExtension" */; + buildPhases = ( + EFC0F522749728A908AFAA2F /* [CP] Check Pods Manifest.lock */, + 035A1D1D1EBB38BD00A4E721 /* Sources */, + 035A1D1E1EBB38BD00A4E721 /* Frameworks */, + 035A1D1F1EBB38BD00A4E721 /* Resources */, + 48F688B6622DB4DED468C4AD /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RxKeyboardShareExtension; + productName = RxKeyboardShareExtension; + productReference = 035A1D211EBB38BD00A4E721 /* RxKeyboardShareExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 03E8A71D1E35A95B00F7A3EC /* RxKeyboardExample */ = { isa = PBXNativeTarget; buildConfigurationList = 03E8A7301E35A95B00F7A3EC /* Build configuration list for PBXNativeTarget "RxKeyboardExample" */; @@ -150,10 +235,12 @@ 03E8A71C1E35A95B00F7A3EC /* Resources */, E857CEA8F03D723AC93BD7A1 /* [CP] Embed Pods Frameworks */, 02296B7E592B2B46A5A8C875 /* [CP] Copy Pods Resources */, + 03E711911EB9151800921128 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 035A1D2A1EBB38BD00A4E721 /* PBXTargetDependency */, ); name = RxKeyboardExample; productName = Example; @@ -166,10 +253,14 @@ 03E8A7161E35A95B00F7A3EC /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0820; + LastSwiftUpdateCheck = 0830; LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Suyeol Jeon"; TargetAttributes = { + 035A1D201EBB38BD00A4E721 = { + CreatedOnToolsVersion = 8.3.2; + ProvisioningStyle = Automatic; + }; 03E8A71D1E35A95B00F7A3EC = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Automatic; @@ -190,11 +281,20 @@ projectRoot = ""; targets = ( 03E8A71D1E35A95B00F7A3EC /* RxKeyboardExample */, + 035A1D201EBB38BD00A4E721 /* RxKeyboardShareExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 035A1D1F1EBB38BD00A4E721 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 035A1D271EBB38BD00A4E721 /* MainInterface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 03E8A71C1E35A95B00F7A3EC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -222,6 +322,21 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxKeyboardExample/Pods-RxKeyboardExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 48F688B6622DB4DED468C4AD /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxKeyboardExample-RxKeyboardShareExtension/Pods-RxKeyboardExample-RxKeyboardShareExtension-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; D103E37D22DD7DDCE369FBBB /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -234,7 +349,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; E857CEA8F03D723AC93BD7A1 /* [CP] Embed Pods Frameworks */ = { @@ -252,9 +367,32 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxKeyboardExample/Pods-RxKeyboardExample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + EFC0F522749728A908AFAA2F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 035A1D1D1EBB38BD00A4E721 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 035A1D241EBB38BD00A4E721 /* ShareViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 03E8A71A1E35A95B00F7A3EC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -270,6 +408,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 035A1D2A1EBB38BD00A4E721 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 035A1D201EBB38BD00A4E721 /* RxKeyboardShareExtension */; + targetProxy = 035A1D291EBB38BD00A4E721 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 032ABB7C1E35A9F200A3A5D4 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; @@ -279,9 +425,47 @@ name = LaunchScreen.storyboard; sourceTree = ""; }; + 035A1D251EBB38BD00A4E721 /* MainInterface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 035A1D261EBB38BD00A4E721 /* Base */, + ); + name = MainInterface.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 035A1D2C1EBB38BD00A4E721 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 45C2E6E8F6E3F0046BF9AE7E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + INFOPLIST_FILE = RxKeyboardShareExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.RxKeyboardExample.RxKeyboardShareExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 035A1D2D1EBB38BD00A4E721 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B1027686BB7DB922EB0CFF9E /* Pods-RxKeyboardExample-RxKeyboardShareExtension.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + INFOPLIST_FILE = RxKeyboardShareExtension/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = kr.xoul.RxKeyboardExample.RxKeyboardShareExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; 03E8A72E1E35A95B00F7A3EC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -377,6 +561,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = FF066ACB76646CE5837B517B /* Pods-RxKeyboardExample.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -390,6 +575,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = C2DC646E6858079F25D2BFF4 /* Pods-RxKeyboardExample.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -402,6 +588,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 035A1D2E1EBB38BD00A4E721 /* Build configuration list for PBXNativeTarget "RxKeyboardShareExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 035A1D2C1EBB38BD00A4E721 /* Debug */, + 035A1D2D1EBB38BD00A4E721 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 03E8A7191E35A95B00F7A3EC /* Build configuration list for PBXProject "RxKeyboardExample" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Example/RxKeyboardShareExtension/Base.lproj/MainInterface.storyboard b/Example/RxKeyboardShareExtension/Base.lproj/MainInterface.storyboard new file mode 100644 index 0000000..09f162c --- /dev/null +++ b/Example/RxKeyboardShareExtension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RxKeyboardShareExtension/Info.plist b/Example/RxKeyboardShareExtension/Info.plist new file mode 100644 index 0000000..6403273 --- /dev/null +++ b/Example/RxKeyboardShareExtension/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + RxKeyboardShareExtension + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + TRUEPREDICATE + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.share-services + + + diff --git a/Example/RxKeyboardShareExtension/ShareViewController.swift b/Example/RxKeyboardShareExtension/ShareViewController.swift new file mode 100644 index 0000000..e4f966a --- /dev/null +++ b/Example/RxKeyboardShareExtension/ShareViewController.swift @@ -0,0 +1,53 @@ +// +// ShareViewController.swift +// RxKeyboardShareExtension +// +// Created by Suyeol Jeon on 04/05/2017. +// Copyright © 2017 Suyeol Jeon. All rights reserved. +// + +import UIKit +import Social +import RxKeyboard +import RxSwift +import SnapKit + +class ShareViewController: UIViewController { + let disposeBag = DisposeBag() + let textView = UITextView() + let toolbar = UIToolbar() + + override func viewDidLoad() { + super.viewDidLoad() + self.textView.font = UIFont.systemFont(ofSize: 50) + self.textView.text = (0...100).map { "\($0)" }.joined(separator: "\n") + self.textView.keyboardDismissMode = .interactive + self.view.addSubview(self.textView) + self.view.addSubview(self.toolbar) + + self.textView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + self.toolbar.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.bottom.equalToSuperview() + } + + // Set `gestureValue` for using interactive keyboard tracking + RxKeyboard.instance.gestureView = self.view + RxKeyboard.instance.visibleHeight + .drive(onNext: { [weak self] visibleHeight in + guard let `self` = self else { return } + self.toolbar.snp.updateConstraints { make in + make.bottom.equalTo(-visibleHeight) + } + self.view.setNeedsLayout() + UIView.animate(withDuration: 0) { + self.textView.contentInset.bottom = visibleHeight + self.toolbar.frame.height + self.textView.scrollIndicatorInsets.bottom = self.textView.contentInset.bottom + self.view.layoutIfNeeded() + } + }) + .addDisposableTo(self.disposeBag) + } +} diff --git a/RxKeyboard.xcodeproj/project.pbxproj b/RxKeyboard.xcodeproj/project.pbxproj index 4145ca3..9d837c1 100644 --- a/RxKeyboard.xcodeproj/project.pbxproj +++ b/RxKeyboard.xcodeproj/project.pbxproj @@ -277,6 +277,7 @@ 03A258D41DA94EC50035A85B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; @@ -302,6 +303,7 @@ 03A258D51DA94EC50035A85B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; From 91b2999371b16a8cae547b042aaf894abbcaba62 Mon Sep 17 00:00:00 2001 From: Suyeol Jeon Date: Thu, 4 May 2017 22:01:43 +0900 Subject: [PATCH 4/4] Add a documentation for gestureView API --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index f4cd02a..96bc201 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,16 @@ RxKeyboard.instance.frame > **Note**: In real world, you should use `setNeedsLayout()` and `layoutIfNeeded()` with animation block. See the [example project](https://github.com/RxSwiftCommunity/RxKeyboard/blob/master/Example/Sources/ViewControllers/MessageListViewController.swift#L92-L105) for example. +- 🔗 **I want to use RxKeyboard in App Extension.** + + App Extesion doesn't allow the `UIApplication.shared` API so the pan gesture recognizer cannot automatically track the interactive keybord dismissing. You have to do something manually in the App Extension target: setting `gestureView`. + + ```swift + // ShareViewController.swift + RxKeyboard.instance.gestureView = self.view // add this line on `viewDidLoad()` + RxKeyboard.instance.visibleHeight.drive(...) + ``` + - Anything else? Please open an issue or make a Pull Request. ## Dependencies