1

I have an app that uses a collectionview that scrolls horizontally, and has collectionviewcells inside of it. Everything was going fine until I tried to implement a login/register cell with 2 textfields in it using textfielddelegate. When I press on one of the textfields, the keyboard shows for a split second and then hides. After it does this, the view is pushed down a little bit and if I press the textfield again, it is pushed up and wont come down. Here are some screenshots of what it looks like:

before touching a textfield vs. after I touch a textfield

I get various UICollectionViewFlowLayout errors that call for me to make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes.

The behavior of the UICollectionViewFlowLayout is not defined because: 2017-04-26 13:55:03.199199-0400 Eyetube[1500:243622] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values. 2017-04-26 13:55:03.200490-0400 Eyetube[1500:243622] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x10453ee90>, and it is attached to <UICollectionView: 0x104806800; frame = (0 0; 768 960); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x17405a610>; layer = <CALayer: 0x17002f0a0>; contentOffset: {2304, 0}; contentSize: {3072, 910}> collection view layout: <UICollectionViewFlowLayout: 0x10453ee90>. 2017-04-26 13:55:03.200575-0400 Eyetube[1500:243622] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

I tried debugging this multiple times, but it isn't too helpful in finding where exactly the error is coming from. I've been stuck on this issue for hours and can't seem to figure it out.

Where I initialize my layout in my collectionviewcontroller:

func setupCollectionView() {

    if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
        flowLayout.scrollDirection = .horizontal
        flowLayout.minimumLineSpacing = 0
    }

    collectionView?.backgroundColor = UIColor.white
    collectionView?.register(VideoFeedCell.self, forCellWithReuseIdentifier: cellId)
    collectionView?.register(ChannelFeedCell.self, forCellWithReuseIdentifier: channelCellId)
    collectionView?.register(ARFeedCell.self, forCellWithReuseIdentifier: augmentedRealityCellId)
    collectionView?.register(LoginRegisterCell.self, forCellWithReuseIdentifier: loginRegisterCellId)

    collectionView?.contentInset = UIEdgeInsetsMake(0, 0, 50, 0)
    collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 50, 0)

    collectionView?.isPagingEnabled = true

}

My sizeForItemAt func, also in my collectionviewcontroller (P.S., I am subtracting 50 from the height because of the bottom menubar I have added as a subview of the view. I also changed the collectionview's contentInset and scrollIndicatorInsets because of this):

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let cellSize = CGSize(width: view.frame.width, height: view.frame.height - 50)

    return cellSize
}

Here is the complete code of the collectionviewcell, where I am having the issues:

import UIKit

class LoginRegisterCell: BaseCell, UITextFieldDelegate {

let logoImageView: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "eyetube_logo_font")
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFit
    return imageView
}()

let emailTextField: LeftPaddedTextField = {
    let tf = LeftPaddedTextField()
    tf.keyboardType = .emailAddress
    tf.placeholder = "Enter email"
    tf.substituteFontName = "SourceSansPro-Regular"
    tf.layer.borderColor = UIColor.rgb(220, green: 220, blue: 220).cgColor
    tf.layer.borderWidth = 1
    tf.translatesAutoresizingMaskIntoConstraints = false
    return tf
}()

let passwordTextField: LeftPaddedTextField = {
    let tf = LeftPaddedTextField()
    tf.placeholder = "Enter password"
    tf.substituteFontName = "SourceSansPro-Regular"
    tf.layer.borderColor = UIColor.rgb(220, green: 220, blue: 220).cgColor
    tf.layer.borderWidth = 1
    tf.isSecureTextEntry = true
    tf.translatesAutoresizingMaskIntoConstraints = false
    return tf
}()

lazy var loginButton: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor.rgb(225, green: 31, blue: 40)
    button.titleLabel?.font = UIFont(name: "SourceSansPro-SemiBold", size: 20)
    button.setTitle("Log In", for: .normal)
    button.setTitleColor(UIColor.white, for: .normal)
    button.translatesAutoresizingMaskIntoConstraints = false
    button.addTarget(self, action: #selector(handleLogin), for: .touchUpInside)

    return button
}()

lazy var registerLink: UIButton = {
    let button = UIButton(type: .system)
    button.setTitle("Don't have an account? Register here", for: .normal)
    button.translatesAutoresizingMaskIntoConstraints = false
    button.titleLabel?.font = UIFont(name: "SourceSansPro-Regular", size: 18)
    button.setTitleColor(UIColor.darkGray, for: .normal)
    let underlineAttribute = [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue]
    let underlineAttributedString = NSAttributedString(string: (button.titleLabel?.text)!, attributes: underlineAttribute)
    button.titleLabel?.attributedText = underlineAttributedString
    button.addTarget(self, action: #selector(handleRegister), for: .touchUpInside)

    return button
}()

var containerView: UIView!

override func setupViews() {
    super.setupViews()

    self.emailTextField.delegate = self
    emailTextField.returnKeyType = .next
    self.passwordTextField.delegate = self
    passwordTextField.returnKeyType = .done

    containerView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height))
    containerView.backgroundColor = .green
    addSubview(containerView)

    containerView.addSubview(logoImageView)
    containerView.addSubview(emailTextField)
    containerView.addSubview(passwordTextField)
    containerView.addSubview(loginButton)
    containerView.addSubview(registerLink)

    setupLogoImageView()
    setupInputs()
    setupLoginButton()
    setupRegisterLink()
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

func handleLogin() {

    //first check if the email/password textfields are empty or not
    guard let email = emailTextField.text , !email.isEmpty else {
        let alert = UIAlertView (title: "Invalid Email", message: "Please enter an email to log in", delegate: self, cancelButtonTitle: "OK")
            alert.show()
        return
    }

    guard let password = passwordTextField.text , !password.isEmpty else {
        let alert = UIAlertView (title: "Invalid Password", message: "Please enter a password to log in", delegate: self, cancelButtonTitle: "OK")
            alert.show()
        return
    }

    //create session here
    ApiLoginAuthentication.sharedInstance.login_now(username: email, password: password, onCompletion: {(loginSuccessful: Bool) -> Void in

        guard (loginSuccessful) else {
            DispatchQueue.main.async {
                let alert = UIAlertView (title: "Invalid Account info", message: "The account information entered is invalid. Please log in with a valid account.", delegate: self, cancelButtonTitle: "OK")
                alert.show()
            }
            return
        }

        DispatchQueue.main.async {
            self.emailTextField.text = ""
            self.passwordTextField.text = ""
        }
        print("the login was successful")
    })
        /**
        let profileUrl: String = "https://eyetube.net/user/profile.asp"
        ApiLoginAuthentication.sharedInstance.getContent(contentUrl: profileUrl, onCompletion: {(responseString: String, isLoggedIn: Bool) -> Void in
            print(responseString)
            print("user status: \(isLoggedIn)")

            let json: Any?
            do {
                let data: NSData = responseString.data(using: String.Encoding.utf8)! as NSData
                json = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)
                print(json)
            } catch let error {
                print("error: \(error)")
            }
        })**/
}

func handleRegister() {
    let eyetubeRegisterLink = "https://eyetube.net/user/register.asp?rUrl="
    UIApplication.shared.openURL(URL(string: eyetubeRegisterLink)!)
}

func setupLogoImageView() {
    var sizeConstant: CGFloat!
    var centerYConstant: CGFloat!
    if UI_USER_INTERFACE_IDIOM() == .pad {
        sizeConstant = 400
        centerYConstant = -260
    } else {
        sizeConstant = 200
        centerYConstant = -160
    }
    NSLayoutConstraint(item: logoImageView, attribute: .centerY, relatedBy: .equal, toItem: containerView, attribute: .centerY, multiplier: 1, constant: centerYConstant!).isActive = true
    NSLayoutConstraint(item: logoImageView, attribute: .centerX, relatedBy: .equal, toItem: containerView, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: logoImageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: sizeConstant).isActive = true
    NSLayoutConstraint(item: logoImageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: sizeConstant).isActive = true
}

func setupInputs() {
    var widthConstant: CGFloat!
    var leftConstant: CGFloat!
    if UI_USER_INTERFACE_IDIOM() == .pad {
        widthConstant = -64
        leftConstant = 32
    } else {
        widthConstant = -32
        leftConstant = 16
    }
    NSLayoutConstraint(item: emailTextField, attribute: .top, relatedBy: .equal, toItem: logoImageView, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: emailTextField, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: leftConstant).isActive = true
    NSLayoutConstraint(item: emailTextField, attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: 1, constant: widthConstant).isActive = true
    NSLayoutConstraint(item: emailTextField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 50).isActive = true

    NSLayoutConstraint(item: passwordTextField, attribute: .top, relatedBy: .equal, toItem: emailTextField, attribute: .bottom, multiplier: 1, constant: 8).isActive = true
    NSLayoutConstraint(item: passwordTextField, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: leftConstant).isActive = true
    NSLayoutConstraint(item: passwordTextField, attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: 1, constant: widthConstant).isActive = true
    NSLayoutConstraint(item: passwordTextField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 50).isActive = true
}

func setupLoginButton() {
    NSLayoutConstraint(item: loginButton, attribute: .centerX, relatedBy: .equal, toItem: containerView, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: loginButton, attribute: .top, relatedBy: .equal, toItem: passwordTextField, attribute: .bottom, multiplier: 1, constant: 16).isActive = true
    NSLayoutConstraint(item: loginButton, attribute: .width, relatedBy: .equal, toItem: passwordTextField, attribute: .width, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: loginButton, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 50).isActive = true
}

func setupRegisterLink() {
    NSLayoutConstraint(item: registerLink, attribute: .centerX, relatedBy: .equal, toItem: containerView, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: registerLink, attribute: .top, relatedBy: .equal, toItem: loginButton, attribute: .bottom, multiplier: 1, constant: 12).isActive = true
    NSLayoutConstraint(item: registerLink, attribute: .width, relatedBy: .equal, toItem: loginButton, attribute: .width, multiplier: 1, constant: 0).isActive = true
    NSLayoutConstraint(item: registerLink, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 40).isActive = true
}

}

c.schell
  • 11
  • 2
  • Do you have code in the view controller that is triggered when the keyboard is shown? – DonMag Apr 27 '17 at 13:25
  • @DonMag I tried to add keyboardWillShow/keyboardWillHide methods in the controller, but I was having the same issues so I got rid of them before I posted this – c.schell Apr 28 '17 at 16:09
  • Still not answered? How did you solve this? I have the same issue :( – Buglinjo Dec 01 '17 at 03:21

0 Answers0