Keyboard Layout Breaks Into UICollectionViewController

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

Do you have an idea why the frame changes this way?

I have included the most important parts below or you can find a test project here: https://github.com/johntiror/testAutomaticPush/tree/master

UIViewController (just starts 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 } } 

enter image description here

Many thanks

+7
ios swift uicollectionview uicollectionviewlayout
source share
4 answers

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

You might not want to go with CollectionViewController for this use case. If you decide to use it, I also posted another answer. Here's the fastest way to move a CollectionView into a ViewController. This solves your problem, but does not take into account autorun.

1) Replace these lines in the ViewController:

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

from

 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 bottom of the 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 remove the CollectionViewController, as it is now replaced.

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

+3
source share

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

Add the following to the CollectionViewController class:

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Try commenting out this line to see the animation. It 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) } 
+1
source share

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

when you have several text views, it is so difficult, so the best solution is β†’

step 1: provide the delegate with UITextFieldDelegate

 class ScrollViewController: UIViewController,UITextFieldDelegate { 

Step 2: create a new IBOutlet, but do not connect to the text field in the storyboard.

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

Step 3: write these two methods when the user focus on the text object passes the link and stores in activeTextField.

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

Step 4: set the 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 methods for the 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) } 
+1
source share

What I find unusual in your code is that you put your text box inside a cell in your container view. I'm not sure what else you plan to insert into this type of container ... but the presence of a text field in it is a bit strange.

Now, having said that ... the problem you are experiencing is this: when the keyboard shows, the system has two competing goals. First, he tries to scroll the contents of the collection view so that the text field remains visible. It gives a big leap. He then tries to adjust the size of the collection view to get rid of it, but due to the flow layout setting, this is really confusing. If you look in the log, you will see a lot:

2017-05-02 23: 39: 30.671 automaticPush [31629: 1628527] The behavior of the UICollectionViewFlowLayout is not defined because: 2017-05-02 23: 39: 30.671 automaticPush [31629: 1628527] the height of the element must be less than the height of the UICollectionView minus insertion sections up and lower values, minus the upper and lower values ​​of the content insertion. 2017-05-02 23: 39: 30.672 automaticPush [31629: 1628527] The corresponding Instance is UICollectionViewFlowLayout, and it is bound to; layer =; contentOffset: {0, 0}; contentSize: {3750, 667}> collection layout :. 2017-05-02 23: 39: 30.672 automaticPush [31629: 1628527] Make a symbolic breakpoint on UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

Because the system is desperate to align the limitations of your collection view with an attempt to keep the text visible

In general, I would suggest that you put your OUTSIDE text view in the collection view.

-one
source share

All Articles