When changing the insets of a scroll view, they undesirably animate with the keyboard showing and hiding
This is for the messaging part of my app. When I want to bring up the keyboard, I need to instantly change the size of the scroll view of the collection view that displays the messages
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
@IBOutlet weak var myCollectionView: UICollectionView!
@IBOutlet weak var textfield: UITextField!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = UIColor.random()
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 50)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardDidHide), name: UIResponder.keyboardDidHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@objc func handleKeyboardDidHide(notification: NSNotification){
//we only wanna do this if we're at the bottom
// if checkIfScrolledToPosition(distanceFromBottom: 0) {
//
// self.scrollToBottomOfCollectionView(animated: true)
// }
}
@objc func handleKeyboardDidShow(notification: NSNotification){
//temp commented for testing
// if shouldScrollToBottomOnceKeyboardShow{
// self.scrollToBottomOfCollectionView(animated: true)
// shouldScrollToBottomOnceKeyboardShow = false
// }
}
@objc func handleKeyboardNotification(notification: NSNotification?){
if let keyboardFrame: NSValue = notification?.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
let isKeyboardShowing = notification!.name == UIResponder.keyboardWillShowNotification
if isKeyboardShowing{
setCollectionViewScrollInsets(heightFromBottom: keyboardHeight)
}else{
setCollectionViewScrollInsets(heightFromBottom: 0)
}
}
}
@IBAction func button(_ sender: Any) {
textfield.resignFirstResponder()
}
func setCollectionViewScrollInsets(heightFromBottom: CGFloat){
// messagesCollectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightFromBottom, right: 0)
myCollectionView.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: heightFromBottom, right: 0)
//myCollectionView.layoutIfNeeded()//without this is seems to cause severe fuck up
}
}
I expect the scroll view to instantly change size, but the actual change is gradual and animated with the keyboard. I suspect it is to do with the layout being updated within some hidden away method related to the keyboard showing, but that is affecting the rest of the view.
A possible solution to this problem could be to force the scroll view to stay scrolled to the bottom while the keyboard is showing, so I don't have to worry about the insets changing instantly, if anyone knows how to do that.
You are performing your layout within the animation of the keyboard (because the notification is sent during this animation), so your animatable changes (e.g., your manipulation of the insets and frame changes from your subsequent explicit layout pass) are animated within that animation. You can use [UIView performWithoutAnimation:]
if you really need to perform these manipulations without animation.