Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow views to move based on keyboard even when not having first responders #335

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Source/Infra/EKContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand All @@ -569,7 +574,7 @@ extension EKContentView {
}

@objc func keyboardWillShow(_ notification: Notification) {
guard containsFirstResponder else {
guard shouldAnimateOnKeyboardChanges() else {
return
}
keyboardState = .visible
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,40 @@ 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

/** 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 */
Expand Down