SwiftKickMobile / SwiftMessages

A very flexible message bar for UIKit and SwiftUI.
MIT License
7.24k stars 741 forks source link

How do I show a message that appears above the keyboard, when the keyboard is already visible? #533

Open jmarr opened 8 months ago

jmarr commented 8 months ago

If I do config.keyboardTrackingView = KeyboardTrackingView(), I can show a message and then make the keyboard visible, and the message slides up so that it remains above the keyboard (though I do see the issue mentioned in #496). However, once the keyboard is visible, if I show another message, it appears at the bottom of the view, behind the keyboard.

Next I tried creating and installing a KeyboardTrackingView into my view controller's view hierarchy and setting that as the config.keyboardTrackingView. Then if I show a message after the keyboard is up, the message appears above the keyboard. However, if I dismiss the keyboard, bring the keyboard back up, and then show another message, the message appears behind the keyboard.

Finally, I tried creating and installing a KeyboardTrackingView into my view controller's view hierarchy and then creating another UIView with its top anchored to the top of the viewController's view and its bottom anchored to the top of the KeyboardTrackingView and then using that view for the presentationContext. This generally seems to work (though it also suffered from the issue mentioned in #496). Would this be the recommended approach or should it work when using the config.keyboardTrackingView?

wtmoose commented 8 months ago

I'm super busy, but I will do my best to take a look at this soon. It is a fairly obscure feature, so I wouldn't be surprised if it has some rough edges.

wtmoose commented 8 months ago

I took a look and found a couple of issues:

First, KeyboardTrackingView is based on notifications. If you create a new one after the keyboard has already appeared, it won't know the current state of the keyboard. This was designed before keyboard layout margins existed :(

I have a slightly modified version of KeyboardTrackingView that works if you hold onto it in your view controller and reuse the same instance with each message view. However, there is still a small issue related to safe area. All of the nib files provided with SwiftMessages rely on the layoutMargins property to position the content. When you show a message, the appropriate layout margins are calculated based on the safe area. This can cause problems when combined with the keyboard tracking behavior:

  1. If the message is displayed before the keyboard appears, the bottom margin is too big after the keyboard pushes it up.
  2. If the message is displayed before the keyboard appears, the bottom margin is too small if the keyboard is dismissed, leaving the message view in the safe area.

Again, this stuff was designed before safe area existed :(

I'm not going to have time to rework the layout system for this particular issue. However, if you're willing to use your own view that internally constrains the content to bottom safe area, rather than one of the bundled nib files, I think my updated KeyboardTrackingView will probably work for you.

Let me know what you think.

jmarr commented 8 months ago

Awesome, thanks for looking into this. I saw you made some changes in 9.0.9, so I'll play around with that and creating our own view and let you know how it goes.

wtmoose commented 8 months ago

The idea with the updated KeyboardTrackingView is that your view controller needs to create and hold onto a single instance and use that instance for each message. That way it retains the memory of the state of the keyboard. For the view, you need to set it up such that it uses Auto Layout to avoid the safe area rather than having SwiftMessages calculate the margins. I can help out with that if you get stuck.

jmarr commented 8 months ago

Great! I've installed a KeyboardTrackingView in my view controller and modified a copy of the CardView nib to constrain the bottom of the corner rounding view to the bottom safe area (minus an 8pt margin) and that seems to be working well. Thanks so much!