diff --git a/Source/Infra/EKContentView.swift b/Source/Infra/EKContentView.swift index ba3bd520..543ddf4c 100644 --- a/Source/Infra/EKContentView.swift +++ b/Source/Infra/EKContentView.swift @@ -168,6 +168,8 @@ class EKContentView: UIView { // Setup keyboard constraints switch attributes.positionConstraints.keyboardRelation { case .bind(offset: let offset): + fallthrough + case .bindAlways(offset: let offset): if let screenEdgeResistance = offset.screenEdgeResistance { resistanceConstraint = layoutToSuperview(.top, relation: .greaterThanOrEqual, offset: screenEdgeResistance, priority: .defaultLow) } @@ -542,9 +544,12 @@ extension EKContentView { private func animate(by userInfo: [AnyHashable: Any]?, entrance: Bool) { - // Guard that the entry is bound to the keyboard - guard case .bind(offset: let offset) = attributes.positionConstraints.keyboardRelation else { - return + // Guard that the entry is bound to the keyboard and has offset + guard + attributes.positionConstraints.keyboardRelation.isBound, + let offset = attributes.positionConstraints.keyboardRelation.offset + else { + return } // Convert the user info into keyboard attributes @@ -569,7 +574,7 @@ extension EKContentView { } @objc func keyboardWillShow(_ notification: Notification) { - guard containsFirstResponder else { + guard shouldAnimateOnKeyboardChanges() else { return } keyboardState = .visible @@ -585,11 +590,19 @@ extension EKContentView { } @objc func keyboardWillChangeFrame(_ notification: Notification) { - guard containsFirstResponder else { + guard shouldAnimateOnKeyboardChanges() else { return } animate(by: notification.userInfo, entrance: true) } + + private func shouldAnimateOnKeyboardChanges() -> Bool { + switch attributes.positionConstraints.keyboardRelation { + case .unbind: return false + case .bindAlways(offset: _): return true + case .bind(offset: _): return containsFirstResponder + } + } } // MARK: Responds to user interactions (tap / pan / swipe / touches) diff --git a/Source/Model/EntryAttributes/EKAttributes+PositionConstraints.swift b/Source/Model/EntryAttributes/EKAttributes+PositionConstraints.swift index 7c3e539d..0366c0df 100644 --- a/Source/Model/EntryAttributes/EKAttributes+PositionConstraints.swift +++ b/Source/Model/EntryAttributes/EKAttributes+PositionConstraints.swift @@ -107,11 +107,17 @@ public extension EKAttributes { } } - /** Bind the entry's bottom to the keyboard's top with an offset. + /** Bind the entry's bottom to the keyboard's top with an offset when keyboard contains first reponder Additionally, the top edge of the screen can have a resistance offset which the entry isn't able to cross. The resistance is mostly used when the device orientation changes and the entry's frame crosses the screen bounds. Current isn't supported with center entry position.*/ case bind(offset: Offset) + + /** Bind the entry's bottom to the keyboard's top with an offset. + Additionally, the top edge of the screen can have a resistance offset which the entry isn't able to cross. + The resistance is mostly used when the device orientation changes and the entry's frame crosses the screen bounds. + Current isn't supported with center entry position.*/ + case bindAlways(offset: Offset) /** Entry is unbound to the keyboard. It's location doesn't change. */ case unbind @@ -119,12 +125,22 @@ public extension EKAttributes { /** Returns true if the entry is bound to the keyboard */ public var isBound: Bool { switch self { - case .bind(offset: _): + case .bind(offset: _), .bindAlways(offset: _): return true case .unbind: return false } } + + var offset: Offset? { + switch self { + case .bindAlways(offset: let offset): + return offset + case .bind(offset: let offset): + return offset + default: return nil + } + } } /** Rotation related position constraints */