Keyboard breaks layout in UICollectionViewController

I have a horizontal UICollectionViewController where each cell contains a UITextView at the bottom of the cell. When I tap inside the UITextView, while the keyboard is appearing, the CollectionView's height is reduced 260 points (which I notice is the height of the keyboard) and then increases 130 points, so the final height is 130 points less than desired.

Do you have any idea why the frame changes in this manner?

I've included the most relevant parts below, or you can find the test project here: https://github.com/johntiror/testAutomaticPush/tree/master

UIViewController (simply launches CollectionViewController):

class ViewController: UIViewController {
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let layout = UICollectionViewFlowLayout()
    layout.itemSize = view.bounds.size
    layout.scrollDirection = .horizontal
    layout.minimumLineSpacing = 0
    let fsPicVC = CollectionViewController(collectionViewLayout: layout)
    self.present(fsPicVC, animated: true) { }
  }
}

CollectionViewController:

class CollectionViewController: UICollectionViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    self.collectionView!.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")                
  }

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)    

    return cell
  }
}

在这里输入图像描述

Thanks very much


First I have to give my two cents that storyboards are great :)

You may not want to go with CollectionViewController for this use case. If you decide to use it, I've also posted another answer. Here's the quickest way to move your CollectionView to ViewController. This solves your problem but doesn't account for autolayout.

1) Replace these lines in ViewController:

let fsPicVC = CollectionViewController(collectionViewLayout: layout)
self.present(fsPicVC, animated: true) { }

with

let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.dataSource = self
view.addSubview(collectionView)

2) Add this to the very bottom of ViewController (outside the ViewController class):

extension ViewController: UICollectionViewDataSource {

  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
  }

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 10
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)

    // Configure the cell

    return cell
  }
}

Finally, you can delete CollectionViewController, as it has now been replaced.

PS You also probably want to 1) extend ViewController to conform to UICollectionViewDelegateFlowLayout and 2) make collectionView global.


If you want to use CollectionViewController, here's a possible solution (if you want to switch to a generic ViewController see my other answer).

Add the following to your CollectionViewController class:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Try commenting out this line to see the animation. It's included so the user doesn't see the fade effect
    collectionView?.backgroundColor = UIColor.orange

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    NotificationCenter.default.removeObserver(self)
}

func keyboardWillChangeFrame(notification: NSNotification) {

    guard let info = notification.userInfo else {return}
    guard let keyboardFrameEndValue = info[UIKeyboardFrameEndUserInfoKey] as? NSValue else {return}
    let keyboardFrameEnd = keyboardFrameEndValue.cgRectValue

    var itemSize = view.bounds.size
    itemSize.height = keyboardFrameEnd.origin.y

    guard let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout else {return}
    layout.itemSize = itemSize

    collectionView?.setCollectionViewLayout(layout, animated: true)
}

Demo link : https://github.com/harshilkotecha/UIScrollViewWhenKeyboardAppearInSwift3

when you have multiple textview it is so difficult so best solution ->

step 1 : Give Delegate to UITextFieldDelegate

class ScrollViewController: UIViewController,UITextFieldDelegate {

step 2 :create new IBOutlet but don't connect with any text field in storyboard.

//  get current text box when user Begin editing
    @IBOutlet weak var activeTextField: UITextField?

step 3 : write this two method when user focus on text filed object pass the reference and store in activeTextField.

// get current text field
    func textFieldDidBeginEditing(_ textField: UITextField)
    {
        activeTextField=textField;
    }
    func textFieldDidEndEditing(_ textField: UITextField)
    {
        activeTextField=nil;
    }

step 4 : set Notification in viewdidload() setNotificationKeyboard

override func viewWillAppear(_ animated: Bool) {
            // call method for keyboard notification
            self.setNotificationKeyboard()
    }

    // Notification when keyboard show
    func setNotificationKeyboard ()  {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: .UIKeyboardWillHide, object: nil)
    }

step 5 : two method for Keyboard appear and disappear.

func keyboardWasShown(notification: NSNotification)
    {
        var info = notification.userInfo!
        let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height+10, 0.0)
        self.scrollView.contentInset = contentInsets
        self.scrollView.scrollIndicatorInsets = contentInsets
        var aRect : CGRect = self.view.frame
        aRect.size.height -= keyboardSize!.height
        if let activeField = self.activeTextField
        {
            if (!aRect.contains(activeField.frame.origin))
            {
                self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
            }
        }
    }
// when keyboard hide reduce height of scroll view


 func keyboardWillBeHidden(notification: NSNotification){
        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0,0.0, 0.0)
        self.scrollView.contentInset = contentInsets
        self.scrollView.scrollIndicatorInsets = contentInsets
        self.view.endEditing(true)
    }
链接地址: http://www.djcxy.com/p/96232.html

上一篇: Google搜索与Alamofire失败(iOS,Swift,JSON,HTML)

下一篇: 键盘在UICollectionViewController中断布局