Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
  }
}

enter image description here

Thanks very much

like image 804
Stefano Giacone Avatar asked Apr 30 '17 08:04

Stefano Giacone


2 Answers

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.

like image 152
mmd1080 Avatar answered Sep 18 '22 03:09

mmd1080


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)
    }
like image 44
Sakir Sherasiya Avatar answered Sep 22 '22 03:09

Sakir Sherasiya