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