Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muukii/cb33b05756999480cc3500c556425e63 to your computer and use it in GitHub Desktop.
Save muukii/cb33b05756999480cc3500c556425e63 to your computer and use it in GitHub Desktop.
//
import AsyncDisplayKit
import Foundation
import KeyboardGuide
import AppFoundation
/**
A sub-class of ASCollectionNode that supports handling the height of the Keyboard.
Using `KeyboardGuide`, it changes its contentInset and scroll-indicator regarding the relative height of the Keyboard.
*/
open class Experimental_KeyboardCollectionWrapperNode: ASDisplayNode, UIGestureRecognizerDelegate {
public final override var supportsLayerBacking: Bool {
false
}
public let collectionNode: ASCollectionNode
private var isTrackingKeyboardEnabled: Bool = false
private var observer: Observer?
private lazy var panGesture = UIPanGestureRecognizer(
target: self,
action: #selector(handlePanGesture(_:))
)
public init(collectionNode: ASCollectionNode) {
self.collectionNode = collectionNode
super.init()
addSubnode(collectionNode)
}
open override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASWrapperLayoutSpec(layoutElement: collectionNode)
}
public func enableKeyboardTracking() {
ensureMainThread()
assert(isTrackingKeyboardEnabled == false)
isTrackingKeyboardEnabled = true
self.panGesture.delegate = self
view.addGestureRecognizer(self.panGesture)
setNeedsLayout()
layoutIfNeeded()
}
open override func didLoad() {
super.didLoad()
workaround: do {
/**
If we face something issue, try this below thing.
https://github.com/niw/KeyboardGuide#the-important-layout-behavior
The important layout behavior
If your view doesn’t have any sub views that have at least one constraint to view.keyboardSafeArea.layoutGuide, UIKit MAY NOT call layoutSubviews (or similar callbacks such as viewDidLayoutSubviews).
Because in general, the keyboard safe area has a relative layout relationship between the keyboard position where is outside of the view but in the screen, UIKit doesn’t know that relationship without a constraint.
For example, on iOS 13, if a view controller is presented as a modal on iPad in portrait, when the keyboard is appearing, that modal view controller is moved upwards by UIKit. This move changes the relative position of your view to the keyboard, however, UIKit doesn’t call your layoutSubviews (which is obvious,) but for keyboard safe area, you MAY need to re lay out your sub views.
Therefore, you MAY need to add at least one constraint to view.keyboardSafeArea.layoutGuide from one of your sub views, to let UIKit knows view has that relationship.
*/
let c = view.keyboardSafeArea.layoutGuide.leftAnchor.constraint(equalTo: view.leftAnchor)
c.priority = .fittingSizeLevel
c.isActive = true
}
let o = Observer(onChanged: { [weak self] in
guard let self = self else {
return
}
if self.isTrackingKeyboardEnabled {
let bottomInset = self.view.keyboardSafeArea.insets.bottom
if self.collectionNode.contentInset.bottom != bottomInset {
self.collectionNode.contentInset.bottom = bottomInset
self.collectionNode.view.scrollIndicatorInsets.bottom = bottomInset
}
}
})
self.observer = o
KeyboardGuide.shared.addObserver(o)
}
deinit {
if let observer = observer {
KeyboardGuide.shared.removeObserver(observer)
}
}
@objc
private func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
guard let view = gesture.view else {
assertionFailure()
return
}
let location = gesture.location(in: view)
if location.y > (view.frame.maxY - view.keyboardSafeArea.insets.bottom) {
view.endEditing(true)
}
}
public final func gestureRecognizer(
_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer
) -> Bool {
return true
}
private final class Observer: NSObject, KeyboardGuideObserver {
private let onChanged: () -> Void
init(onChanged: @escaping () -> Void) {
self.onChanged = onChanged
}
func keyboardGuide(_ keyboardGuide: KeyboardGuide, didChangeDockedKeyboardState dockedKeyboardState: KeyboardState?) {
onChanged()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment