Orderella / PopupDialog

A simple, customizable popup dialog for iOS written in Swift. Replaces UIAlertController alert style.
http://www.mwfire.de
Other
3.96k stars 522 forks source link

Opening the keyboard pushes the input view out of the visible scope #314

Closed Johnson145 closed 5 years ago

Johnson145 commented 5 years ago

Report

Environment

Please provide information on your development environment, so we can build with the same scenario.

Dependency management

If you are not using any dependency managers, you can remove this section.

What did you do?

I've added a search bar to the very top of my popup's custom view controller. When I tap into the search bar's input field, the iOS keyboard opens and pushes the popup content to the top.

(After the search bar, there is a table view. Entering text into the search bar filters the table content.)

What did you expect to happen?

At least the search bar's input field should still be visible.

What happened instead?

The top part of the popup gets pushed out of the visible scope. The search bar input gets "lost beyond the status bar".

Further notes

I'm not sure, whether this is a coincidence, but it looks like the popup is moved such that the bottom of the status bar is aligned with the top of the table view. So there seems to be some logic trying to prevent the content lost. However, it's loosing the search bar which is placed before the actual table view content.

The search bar is actually placed into the table's header: tableView.tableHeaderView = searchController.searchBar. Alternatively, I tried to wrap my custom view controller in a navigation controller to move the search bar into the navigation bar: navigationController?.navigationBar.topItem?.titleView = searchController.searchBar. The result remains the same.

I'm getting a similar, but not identical behavior, if I simply force the popup's custom view controller to have a height larger than the screen height. In that case the top of the custom view controller gets lost. Maybe the popup simply get's centered? Of course, I shouldn't use a height larger than the screen height in the first place. However, it would probably be better to align the popup's top to the bottom of status bar, right?

Johnson145 commented 5 years ago

I solved it by modifying my custom (navigation) controller like follows:

class PopupNavigationController: UINavigationController {

    // this is the height of our view, if no keyboard is visible
    var basicHeight: CGFloat {
        get {
            let windowHeight = self.view.window?.frame.size.height ?? UIScreen.main.bounds.height
            return windowHeight * 0.85
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.setHeightConstraint(height: self.basicHeight)

        // get notified, when the iOS keyboard gets shown or hidden
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIApplication.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIApplication.keyboardWillHideNotification, object: nil)
    }

    @objc func keyboardWillShow(notification: NSNotification) {
        // reduce height to free space for the keyboard
        let info = notification.userInfo!
        let keyboardHeight = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        self.view.setHeightConstraint(height: self.basicHeight - keyboardHeight)

        // animate the height change
        let duration: TimeInterval = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
    }

    @objc func keyboardWillHide(notification: NSNotification) {
        // increase height to the initial basicHeight
        let info = notification.userInfo!
        self.view.setHeightConstraint(height: self.basicHeight)

        // animate the height change
        let duration: TimeInterval = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

So it has a default height, which is required to let the popup show any content in the first place. Furthermore, its height is adjusted whenever the keyboard gets visible/hidden.

I'm not sure whether this is something the user should care about. Maybe there's a smart way to embed a similar behavior as the library's default? At least for custom controllers which explicitly need to handle their height constraints?

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.