Reputation: 19572
This isn't a question about raising the collectionView when the keyboard rises and lowers, that part works fine. This is about the scrollView inside the collectionView not rising with it.
I have a view pinned to the bottom of the screen and inside that view I have a textView. Pinned to the top of the view is a collectionView that's pinned to the top of the screen
-top of viewController
collectionView
containerView that contains a textView
-bottom of viewController
When the textView's textField is tapped I use a notification which detects when the keyboard rises and lowers. It works fine because the collectionView goes up and down like it's supposed to. The problem is the collectionView's contents. If the collectionView's cells fill the screen when the collectionView rises up it's scrollVIew doesn't raise with it so the the cells are behind the keyboard. 2 pics below.
When the keyboard notification is sent I tried changing the collectionView's contentInset, scrollIndicatorInsets, and tried scrolling to the last cell but nothing. The cells just scroll up a tad bit.
@objc fileprivate func keyboardWillShow(notification: Notification) {
guard let keyboardDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return }
guard let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardFrame = keyboardFrame.cgRectValue
let keyboardHeight = keyboardFrame.height
containerViewBottomAnchorConstraint?.isActive = false
containerViewBottomAnchorConstraint = containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -keyboardHeight)
containerViewBottomAnchorConstraint?.isActive = true
// I tried this
let item = tableData.count - 1
let indexPath = IndexPath(item: item, section: 0)
if !tableData.isEmpty {
collectionView.scrollToItem(at: indexPath, at: .bottom, animated: true)
}
// I tried this
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: -keyboardHeight, right: 0)
collectionView.contentInset = contentInsets
collectionView.scrollIndicatorInsets = contentInsets
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
}) { [weak self](_) in
self?.autoScrollToLastCell() // I tried this
}
}
@objc fileprivate func keyboardWillHide(notification: Notification) {
guard let keyboardDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return }
containerViewBottomAnchorConstraint?.isActive = false
containerViewBottomAnchorConstraint = containerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0)
containerViewBottomAnchorConstraint?.isActive = true
UIView.animate(withDuration: keyboardDuration, animations: {
self.view.layoutIfNeeded()
}) { [weak self](_) in
self?.autoScrollToLastCell()
}
}
func autoScrollToLastCell() {
let section = 0
let item = collectionView.numberOfItems(inSection: section) - 1
let index = IndexPath(item: item, section: section)
if item > 0 {
collectionView.scrollToItem(at: index, at: .bottom, animated: true)
}
}
After the keyboard rises the collectionView is up but it's contents aren't
Upvotes: 3
Views: 4326
Reputation: 1076
Changing to keyboardDidShow might solve the problem because keyboardWillShow is called when the keyboard is showing up.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil)
Adding the function will help to scroll the view to the bottom.
@objc func keyboardDidShow() {
self.collectionView.scrollToItem(at: [0, messageList.count - 1],
at: .bottom,
animated: false)
}
Upvotes: 0
Reputation: 2402
This should be the accepted answer:
Add the listener when the keyboard is raised:
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
Then add this function:
@objc func handleKeyboardWillShow(notification: Notification) {
collectionView.scrollToItem(at: IndexPath(row: messagesList.count - 1, section: chatSection), at: .top, animated: false)
}
Note: If you have more than one section, change the section
value
Upvotes: 4