slackhq / PanModal

An elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.
MIT License
3.69k stars 533 forks source link

Issue when laying/placing a view with UITextView on top of the keyboard, this bug is also in the Slack app #164

Open DavidDHansson opened 2 years ago

DavidDHansson commented 2 years ago

Description

THIS ISSUE IS ALSO IN THE OFFICAL SLACK APP (in a way, look at attachment 6)

There is an issue if you want to lay a view with a UITextView on top of a keyboard in the PanModal.

Usually you can simply observe the UIResponder.keyboardDidChangeFrameNotification event and get the height of the keyboard each frame and simply set that as a bottom y offset for the view that should lay on top. - This sometimes dosen't work. (Look at attachment 4 and 5)

Also, site note, because the PanModal has big paddings around the view on iPad (and other big devices), you can't simple take the keyboard height, you have to calculate the height of the bottom padding and use the difference in the padding and the keyboard height to calculate the offset for the view that's gonna lay on top. This is also why in my solution I don't use UIResponder.keyboardDidChangeFrameNotification but UIResponder.keyboardDidShowNotification instead, because we can only calculate the bottom padding, AFTER the PanModal has finished animating and showing. If you were to use the other observer it would look great on iPhone, but would look waaaay off on iPad. Please look at 1, 2 and 3 in the attachments.

What type of issue is this?

Requirements


Bug Report

Reproducible in:

PanModal version: 1.2.7

iOS version: 14.7.1 - iPhone Xs (and in the Slack app on iOS 15.1.1 - iPhone 12) (And probably more versions)

Steps to reproduce:

This can't consistently be reproduced. This has been a hot topic with my coworkers and we simply can't reproduce it. We often get bug reports from users complaining about it. The bug just happens sometimes, only one of my coworkers have experienced this bug irl and they didn't do anything out of the normal that could have caused it.

This bug might be an issue from Apple.

Steps to reproduce, so that in a rare circumstance the bug will appear.

  1. Setup a viewcontroller (A) that extends PanModalPresentable
  2. Setup another viewcontroller (B) with the view and the UITextView that you want to lay on top of the keyboard
  3. B should observe the following and have this function to adjust a view and its padding (in this case the padding textViewBottom and the view textView)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil)
@objc private func keyboardDidShow(notification: NSNotification) {
        guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }

        let topMargin = view.superview?.convert(view.frame.origin, to: nil).y ?? 0.0
        let margins = (UIScreen.main.bounds.height - view.frame.height)
        let bottomSafeArea = (view.window?.safeAreaInsets.bottom ?? 0.0)

        let bottomOffset = margins-topMargin > 0 ? margins-topMargin-bottomSafeArea : 0
        let offset = keyboardSize.height+textViewBottomPadding-bottomSafeArea

        textViewBottom.constant = margins > keyboardSize.height ? -(textViewBottomPadding) : -(offset-bottomOffset)

        UIView.animate(withDuration: 0.1, animations: { [weak self] in
            self?.view.setNeedsLayout()
            self?.view.layoutIfNeeded()
        })
    }

(attachment 2 for drawing explaining the code)

  1. Have A present B with following the configuration B.modalPresentationStyle = .overCurrentContext B.modalTransitionStyle = .crossDissolve
  2. Open the A view on a device and watch the view beautifully lay on top of the keyboard.
  3. Done. Now in some cases due to some unknown reasons the view will be set 10-20 px down - always the same amount of px.

Expected result:

It is excepted that the view sits on top of the keyboard perfectly.

Actual result:

Sometimes the view sits on top of the keyboard, sometimes it is missing some pixels - always the same amount of pixels.

Attachments:

1: The paddings on the PanModal on big device
offsetiPad
2: How I calculated the offset of the view, where the stripes are the keyboard, code is on step 3
calculateOffset
3: Example on iPad of how it should look
offsetiPadWorking
4: Example of how it shouldn't look on iPhone
bug
5: Example of how it should look on iPhone
excpected
6: Example of Slack app having the same issue (although not on the PanModal, I think)
slack example
JMCPH commented 2 years ago

The exact same thing is also happening for me!