Skip to content

FloatingPanel - Improve handling of keyboard closure #509

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

Merged
merged 1 commit into from
Nov 22, 2023
Merged

Conversation

dfeinzimer
Copy link
Collaborator

@dfeinzimer dfeinzimer commented Nov 20, 2023

Closes Apollo 278

Improves handling of keyboard closure.

Will open a 2nd PR once this has merged to get these changes into v.next.


This essentially switches the FloatingPanel over from automatic to manual keyboard avoidance. This allows us to maintain a constant height while the keyboard is closing to rid us of the rubber band effect exhibited in Apollo 278.


Note: This should be tested on a physical device with rounded corners if possible. Simulators still show a little jump with the predictive text bar but I tested a bit on a physical device with rounded corners and couldn't reproduce it there.

predictive_text_bar_jump_in_simulator.mp4

2nd iteration

Current status

Working pretty well

Update FormView.swift

Update FloatingPanel.swift

Update FormView.swift

Update FormView.swift

Update FloatingPanel.swift

Update FormView.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Update FloatingPanel.swift

Place new API
@dfeinzimer dfeinzimer self-assigned this Nov 20, 2023
Comment on lines +51 to +52
/// The current height of the device keyboard.
@State private var keyboardHeight: CGFloat = 0
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracking the height allows us to apply the correct amount of padding to implement manual keyboard avoidance. This height can differ slightly depending on whether the keyboard has a toolbar attached or the predictive text bar is enabled.

Comment on lines -51 to -52
/// A Boolean value indicating whether the keyboard is open.
@State private var keyboardIsOpen = false
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been replaced by keyboardState.

Comment on lines -140 to -143
if shouldSendResign {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
shouldSendResign = false
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissing the keyboard while the user is still dragging can create an issue where the handle moves away from the user's finger. Now we just wait for the gesture to end.

Comment on lines +159 to +161
if $0.translation.height.magnitude > 100 {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the gesture was a significant height difference, then dismiss the keyboard.

Comment on lines -60 to -62
/// A Boolean value indicating whether the resignFirstResponder should be sent for the current
/// drag gesture.
@State private var shouldSendResign = true
Copy link
Collaborator Author

@dfeinzimer dfeinzimer Nov 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to track if we've sent the resign notification any longer because it's sent when the gesture ends now and that only runs once.

@@ -75,6 +74,7 @@ struct FloatingPanel<Content>: View where Content: View {
Divider()
}
content()
.padding(.bottom, isCompact ? keyboardHeight - geometryProxy.safeAreaInsets.bottom : .zero)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Padding the bottom of the content with an amount equal to the height of the keyboard gives us manual avoidance.

We need to take away the bottom safe area height because this height is included in the keyboard frame height on devices with rounded screen corners.

Comment on lines -108 to -110
// When the panel is anchored to the bottom of the screen (compact) ignore the
// device's bottom safe area.
.ignoresSafeArea(.container, edges: isCompact ? .bottom : [])
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has moved into the FloatingPanel view itself. It allows us to locate the two ignoresSafeArea modifiers right next to each other and factor in the state of the keyboard.

@dfeinzimer dfeinzimer requested a review from mhdostal November 20, 2023 21:43
@dfeinzimer dfeinzimer marked this pull request as ready for review November 20, 2023 21:51
Copy link
Member

@mhdostal mhdostal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! There is just a small "bump" animation when the keyboard opens, but I don't think it's too bad. We should get this to the team and see what they think. Nice work!

FloatingPanelAnimation.MP4

@dfeinzimer dfeinzimer merged commit 56dc193 into Forms Nov 22, 2023
@dfeinzimer dfeinzimer deleted the df/apollo278 branch November 22, 2023 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants