UICollectionViewFlowLayout issues with collectionview and textfields - swift

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

Related

'UICollectionView must be initialized with a non-nil layout parameter' problem arises even when layout parameter is set

You can see from the code below that layout parameter has been set inside ViewDidLoad(), but it gives me an error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'UICollectionView must be
initialized with a non-nil layout parameter'
var layer: UICollectionViewFlowLayout = {
var item = UICollectionViewFlowLayout()
item.itemSize = CGSize(width: 100, height: 100)
return item
}()
UICollectionView object has been set in property initializer because obviously I want this UICollectionView object to be accessible globally:
var dataCollectionViews = UICollectionView()
viewDidLoad(){
dataCollectionViews = UICollectionView(frame: CGRect(x: 0, y: 0, width: 0, height: 0) , collectionViewLayout: self.layer)
view.addSubview(dataCollectionViews)
self.dataCollectionViews.delegate = self
self.dataCollectionViews.dataSource = self
self.dataCollectionViews.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewReuse)
self.dataCollectionViews.layer.cornerRadius = 10
self.dataCollectionViews.translatesAutoresizingMaskIntoConstraints = false
self.dataCollectionViews.isHidden = true
changed()
}
When I moved contents inside changed() to inside of viewDidLoad() and initialized dataCollectionViews inside of viewDidLoad(), everything worked as intended, showing UICollectionView object when selecting first button of segmented Control.
#objc func changed() {
if segmentTime.selectedSegmentIndex == 0 {
self.dataCollectionViews.isHidden = false
let dataCollectionTop = NSLayoutConstraint(item: self.dataCollectionViews, attribute: .top, relatedBy: .equal, toItem: sortLabel, attribute: .bottom, multiplier: 1.0, constant: 10)
let dataCollectionLeft = NSLayoutConstraint(item: self.dataCollectionViews, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 10)
let dataCollectionRight = NSLayoutConstraint(item: self.dataCollectionViews, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1.0, constant: -10)
let dataCollectionHeight = NSLayoutConstraint(item: self.dataCollectionViews, attribute: .height, relatedBy: .equal, toItem: self.view, attribute: .height, multiplier: 520/812, constant: 0)
let dataCollectionWidth = NSLayoutConstraint(item: self.dataCollectionViews, attribute: .width, relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 355/375, constant: 0)
NSLayoutConstraint.activate([dataCollectionLeft, dataCollectionRight, dataCollectionHeight, dataCollectionWidth, dataCollectionTop])
}
if segmentTime.selectedSegmentIndex == 1 {
}
if segmentTime.selectedSegmentIndex == 2 {
}
}
I'd love to try to set dataCollectionViews object in property initializer but I know it is not possible, but it seems like dataCollectionViews needs be initialized with UICollectionViewFlowLayout() on first try. What other alternative is available?
How about something like this?
private lazy var collectionView: UICollectionView = {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 188.0, height: 268.0)
let result: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
result.register(CellClass.self, forCellWithReuseIdentifier: "cell")
result.dataSource = self
result.delegate = self
return result
}()

Center button in footerView

I want my button to be in the center of my footerView. I tried several methods but failed every time:
1.
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect.zero)
footerView.backgroundColor = UIColor(rgba: "#F9FAFB")
let button = UIButton(frame: CGRect(x:(footerView.frame.size.width - 30) / 2, y:(footerView.frame.size.height - 30) / 2, width: 30, height: 30)) button.setImage(UIImage(named: "gen-cog"), for: .normal)
button.addTarget(self, action: #selector(footerButtonAction), for: .touchUpInside)
footerView.addSubview(button)
}
Used auto layout, this centers my button but breaks width and height of it, which I set to 30 above.
let centerYCon = NSLayoutConstraint(item: button,
attribute: .centerY,
relatedBy: .equal,
toItem: footerView,
attribute: .centerY,
multiplier: 1.0,
constant: 0.0);
footerView.addConstraint(centerYCon)
let centerXCon = NSLayoutConstraint(item: button,
attribute: .centerX,
relatedBy: .equal,
toItem: footerView,
attribute: .centerX,
multiplier: 1.0,
constant: 0.0);
footerView.addConstraint(centerXCon)
footerView.addSubview(button)
3.
button.center = footerView.center
button.translatesAutoresizingMaskIntoConstraints = false
footerView.addSubview(button)
Now Add two more additional Constraints.
let widthConstraint = NSLayoutConstraint(item: button, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 30)
let heightConstraint = NSLayoutConstraint(item: button, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 30)
button.addConstraints([widthConstraint, heightConstraint])

Setting 2 label in header programatically - not label seen

I'm trying to set 2 labels, one under other with different font size in the header. The function is called like this:
viewController.navigationItem.titleView = self.setHeader()
And code responsible for generating label is :
private func setHeader(agentName: String = "", isTyping: Bool = false) -> UIView {
let headerLabel: UILabel = {
let label = UILabel()
label.text = self.title
label.font = UIFont.systemFont(ofSize: 21)
label.textColor = UIColor.white
return label
}()
let subheaderLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 10)
return label
}()
let headerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(headerLabel)
view.addConstraints([
NSLayoutConstraint(item: headerLabel, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: headerLabel, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: headerLabel, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 16),
NSLayoutConstraint(item: headerLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 16)
])
return view
}()
if (!agentName.isEmpty) {
if (isTyping) {
subheaderLabel.text = agentName + " is typing ..."
} else {
subheaderLabel.text = agentName
}
headerView.addSubview(subheaderLabel)
}
return headerView
}
When I running IOS app there is nothing shown in the header. What is a reason?
I think you need to set the frame for the headerView. So in the initialization code for the headerView, use initializer with frame:
let headerView: UIView = {
// initialize the view with frame
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 35))
// you want to call this on the headerLabel, not on view
headerLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(headerLabel)
view.addConstraints([
NSLayoutConstraint(item: headerLabel, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: headerLabel, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: headerLabel, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 16),
NSLayoutConstraint(item: headerLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 16)
])
return view
}()
Moreover, I believe headerLabel you want to set translatesAutoresizingMaskIntoConstraints on headerLabel rather than on headerView (headerView is positioned through frame and not Autolayout).
Also, notice that you add subheaderLabel to the view, but you never position it, don't forget about it either (although this should cause only subheaderLabel not to be rendered properly).

Centering label and UITextField inside a TableView

New to xcode/swift, spending a couple of days now trying to fix this one. Creating a universal app and having problems getting the constraint working programmatically. I would like to programmatically add a label and a UITextField inside a TableView. The label should always have a fixed width. The text field should have variable width depending on the device.
Here is what is looks like now:
Here is an idea of how it should look:
The label should be a set width. But the textfield should use the available screen.
Here is the code so far:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Setup Cell
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
// Make cell unselectable
cell.selectionStyle = .none
// Process Each Row
let row = indexPath.row
switch row
{
case 0:
let label = UILabel()
label.text = "First Name:"
label.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(40), height: CGFloat(30))
cell.contentView.addSubview(label)
var textField: UITextField = UITextField()
textField.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(170), height: CGFloat(30))
textField.borderStyle = .roundedRect
textField.backgroundColor = UIColor.magenta
textField.text = "TEST"
textField.textColor = UIColor.black
textField.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(textField)
let leadingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: .leftMargin, relatedBy: .equal, toItem: label, attribute: .leftMargin, multiplier: 1.0, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: .rightMargin, relatedBy: .equal, toItem: textField, attribute: .rightMargin, multiplier: 1.0, constant: 0)
cell.contentView.addConstraint(leadingConstraint)
cell.contentView.addConstraint(trailingConstraint)
....
Please let me know if you need additional information before a downvote. Any help would be appreciated. Thanks.
Answer by UpholderOfTruth:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Setup Cell
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
// Make cell unselectable
cell.selectionStyle = .none
// Process Each Row
let row = indexPath.row
switch row
{
case 0:
let label = UILabel()
label.text = "First Name:"
label.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(40), height: CGFloat(30))
label.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(label)
var textField: UITextField = UITextField()
textField.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(170), height: CGFloat(30))
textField.borderStyle = .roundedRect
textField.backgroundColor = UIColor.magenta
textField.text = "TEST"
textField.textColor = UIColor.black
textField.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(textField)
// Horizontal Constraints
cell.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[label(==100)][textField]|", options: .init(rawValue: 0), metrics: nil, views: ["label": label, "textField": textField]))
// Vertical Constraints
cell.contentView.addConstraint(NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0))
cell.contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0))
....
I would suggest go full auto layout and don't mix methods. So first set both view to use auto layout via setting the translatesAutoresizingMaskIntoConstraints to false.
Then either set the constraints visually like this:
cell.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[label(==100)][textField]|", options: .init(rawValue: 0), metrics: nil, views: ["label": label, "textField": textField]))
or with individual constraints like this:
cell.contentView.addConstraint(NSLayoutConstraint(item: label, attribute: .left, relatedBy: .equal, toItem: cell, attribute: .left, multiplier: 1, constant: 0))
cell.contentView.addConstraint(NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 100))
cell.contentView.addConstraint(NSLayoutConstraint(item: label, attribute: .right, relatedBy: .equal, toItem: textField, attribute: .left, multiplier: 1, constant: 0))
cell.contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .right, relatedBy: .equal, toItem: cell, attribute: .right, multiplier: 1, constant: 0))
Of course this just handles horiztonal positioning and sizing you need to do something about vertical positioning and sizing as well but you may be setting that up further down in your code.
Edit:
To centre vertically you can do this:
cell.contentView.addConstraint(NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0))
cell.contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0))
Edit2:
Combining into a single line:
cell.contentView.addConstraints([NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0), NSLayoutConstraint(item: textField, attribute: .centerY, relatedBy: .equal, toItem: cell.contentView, attribute: .centerY, multiplier: 1, constant: 0)])
Edit3:
cell.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[label(==100)][textField]-8-|", options: .init(rawValue: 0), metrics: nil, views: ["label": label, "textField": textField]))
Change these properties:
switch row
{
case 0:
let leadingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: .leftMargin, relatedBy: .equal, toItem: label, attribute: .leftMargin, multiplier: 1.0, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: cell.contentView, attribute: .rightMargin, relatedBy: .equal, toItem: textField, attribute: .rightMargin, multiplier: 1.0, constant: 0)
cell.contentView.addConstraint(leadingConstraint)
cell.contentView.addConstraint(trailingConstraint)
let label = UILabel()
label.text = "First Name:"
//here is the trick: play with x and width. It might also be cell.contentView.size().width
label.frame = CGRect(x: CGFloat(35), y: CGFloat(0), width: CGFloat(cell.frame.width * 1/3), height: CGFloat(30))
cell.contentView.addSubview(label)
var textField = UITextField()
textField.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(cell.frame.width * 2/3), height: CGFloat(30))
textField.borderStyle = .roundedRect
textField.backgroundColor = UIColor.magenta
textField.text = "TEST TEST TEST"
textField.textColor = UIColor.black
textField.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(textField)
Let me know if this works.

Autolayout constraints set in code not appearing in interface builder

I have a custom view that is set in interface builder with top, leading, trailing, height constraints.
In my Custom view i have a title and a button.
Im trying to add to the title a bottom and centerY constraints.
and to the button width, height, bottom, leading constraints.
When i add any constraint i get an warning in interface builder:
Expected: width=600, height=68.
Actual: width=0, height=0
When i run the code everything works, but i cant see anything in interface builder.
code:
#IBDesignable
class UIHeader: UIView {
var delegate: HeaderDelegate?
private lazy var titleLable: UILabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.font = UIFont(name: "Lato-Light", size: 16)
lbl.text = "Title"
return lbl
}()
private lazy var backButton: UIButton = {
let btn = UIButton()
btn.tintColor = UIColor.lightGrayColor()
btn.translatesAutoresizingMaskIntoConstraints = false
let image = UIImage(named: "prev")
if let image = image {
btn.setImage(image.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
btn.addTarget(self, action: #selector(UIHeader.OnBackButtonClickLister(_:)), forControlEvents: .TouchUpInside)
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
}
extension UIHeader {
#IBInspectable
var backButtonImage: UIImage? {
get {
return backButton.imageForState(.Normal)
}
set (newImage) {
backButton.setImage(newImage?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
}
#IBInspectable
var title: String? {
get {
return titleLable.text
}
set (newTitle) {
titleLable.text = newTitle
}
}
}
extension UIHeader {
private func setupView() {
backgroundColor = UIColor.whiteColor()
translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLable)
addSubview(backButton)
//add shadow
layer.shadowColor = UIColor(white: 115/255, alpha: 1.0).CGColor
layer.shadowOpacity = 0.5
layer.shadowRadius = 8
layer.shadowOffset = CGSizeMake(0, -1)
NSLayoutConstraint.activateConstraints([
//Title//
//center x
NSLayoutConstraint(item: titleLable, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .CenterX, multiplier: 1.0, constant: 0),
//bottom
NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: titleLable, attribute: .Bottom, multiplier: 1, constant: 12),
//button//
//bottom
NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: backButton, attribute: .Bottom, multiplier: 1, constant: 4),
//leading
NSLayoutConstraint(item: backButton, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0),
//width
NSLayoutConstraint(item: backButton, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .Width, multiplier: 1, constant: 40),
//height
NSLayoutConstraint(item: backButton, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1, constant: 40)
])
}
}
I also tried to add the constraints with:
addConstraint(NSLayoutConstraint)
cant figure out what is the problem.
Thanks
I removed
translatesAutoresizingMaskIntoConstraints = false
and everything works great.