I create a UICollectionViewCell programmatically when the user start a PanGesture on my CollectionView to reorder the cells (I don't use Apple APIs because I have to personalise the behaviour).
I create a Cell from a custom class WordCollectionViewCell that has an IBOutlet. Here is the code of the class:
class WordCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var wordLabel: UILabel!
}
To create the cell and add it to the CollectionView I use this code:
self.movingCell = {
let mC = WordCollectionViewCell(frame: selectedCell.frame)
// I HAVE TO DO THIS WITH A VARIABLE BECAUSE IF I ASSIGN UILabel() DIRECTLY TO mC.wordlabel, THE APP CRASH BECAUSE wordLabel IS NIL
let label = UILabel()
mC.wordLabel = label
mC.wordLabel.text = selectedCell.wordLabel.text
mC.addSubview(mC.wordLabel)
mC.backgroundColor = selectedCell.backgroundColor
mC.layer.cornerRadius = selectedCell.layer.cornerRadius
mC.tag = selectedIndexPath.row
return mC
}()
self.collectionView.addSubview(self.movingCell)
self.collectionView.addConstraint(NSLayoutConstraint(item: movingCell.wordLabel, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: movingCell, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0))
self.collectionView.addConstraint(NSLayoutConstraint(item: movingCell.wordLabel, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: movingCell, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0))
self.collectionView.addConstraint(NSLayoutConstraint(item: movingCell.wordLabel, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: movingCell, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 0))
self.collectionView.addConstraint(NSLayoutConstraint(item: movingCell.wordLabel, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: movingCell, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 0))
The Cell will follow the PanGesture location.
With this code there are two problems:
I see nothing in movingCell testing on my device;
Why I have can't set UILabel() directly to wordLabel?
Try adding label.translatesAutoresizingMaskIntoConstraints = false
Related
I've an UITableView with some cells, in the first cell I would like to add multiple UILabel. That's the code I am using inside a function in UITableViewCell sub class (called in cellForRowAt):
...
let constantTop = 16
for (index,optional) in optionals.enumerated(){
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "\(optional.name)"
label.tag = 10010132
label.font = CocoFonts.semibold(size: 15)
label.textColor = CocoColors.FedericoMalagoni.textVeryDarkBlue
self.contentView.addSubview(label)
let constant:CGFloat = CGFloat(constantTop * (index + 1))
print(constant)
let horizontalConstraint = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.leading, multiplier: 1, constant: 16)
let verticalConstraint = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.trailing, multiplier: 1, constant: 16)
let height = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 20)
let top = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.lblInfo, attribute: NSLayoutAttribute.bottomMargin, multiplier: 1, constant: constant)
let bottom = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.contentView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: constant)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, top, bottom, height])
}
self.contentView.setNeedsUpdateConstraints()
self.contentView.setNeedsLayout()
self.contentView.layoutIfNeeded()
...
Now,
The labels are over the edge of the cell like this:
The gray separator divide the cell.
Essentially the height of the cell is not updated.
It would be more clear if you could share full implementation of cellForRowAt.
I faced similar issue where cell contents were overlapping. I was adding custom view to the cell as subview.
This happens because Table view re uses its cells. So one solution is to remove old label from the cell before you add new.
for content in cell.contentView.subviews {
content.removeFromSuperview()
}
I have searched SO, but could not find any helpful answer.
I have a storyboard with three (3) textfields, to these textfields I want to make autocomplete textfields.
Am creating tableviews like this
let tblNumbers = UITableView(frame: CGRectMake(16,140,74,200), style: UITableViewStyle.Plain)
var arrStrNo = [String]()
var arrStrNum = [String]()
let tblYears = UITableView(frame: CGRectMake(120,140,74,200), style: UITableViewStyle.Plain)
var arrStrYr = [String]()
var arrStrYears = [String]()
let tblType = UITableView(frame: CGRectMake(222,140,74,200), style: UITableViewStyle.Plain)
var arrStrTyp = [String]()
var arrStrType = [String]()
So programmatically am showing tableviews to just below textfields in shouldChangeCharactersInRange.
table.reloadData()
In storyboard am setting constraints to textfields, now am wondering how can I set constraints to these tableviews, so it should be exactly below the textfields in all size screens.
Programmitically, am trying like below to set constraints to tableviews in viewDidLoad method but its not working
func setConstraintsToYearTableView(){
let topConstraint = NSLayoutConstraint(item: self.tblYears, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 190)
let leadingContraint = NSLayoutConstraint(item: self.tblYears, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 120)
let trailingConstraint = NSLayoutConstraint(item: self.tblYears, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: self.tblYears, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0)
NSLayoutConstraint.activateConstraints([topConstraint, leadingContraint, trailingConstraint, bottomConstraint])
}
I added the following code to center a programmatically added view:
let horizontalConstraint = NSLayoutConstraint(item: newView!, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
view.addConstraint(horizontalConstraint)
It doesn't work. The view is not centered. It is on the left still.
EDIT:
override func viewDidLoad() {
super.viewDidLoad()
newView = LineChartView(frame: CGRectMake(0, 0, 50, 50))
newView?.delegate = self
newView?.drawBordersEnabled = true
newView?.noDataText = "No Data"
newView?.noDataTextDescription = "No Data"
newView?.borderColor = UIColor.blackColor()
self.view.addSubview(newView!)
You need to pick a side my friend, If you are using auto layout, don't initialise your objects with a frame. Try something like this...
var newView:LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
newView = LineChartView()
newView.translatesAutoresizingMaskIntoConstraints = false
newView.delegate = self
newView.drawBordersEnabled = true
newView.noDataText = "No Data"
newView.noDataTextDescription = "No Data"
newView.borderColor = UIColor.blackColor()
self.view.addSubview(newView)
let width = NSLayoutConstraint(item: newView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50)
let height = NSLayoutConstraint(item: newView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50)
newView.addConstraint(width)
newView.addConstraint(height)
let x = NSLayoutConstraint(item: newView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0)
let y = NSLayoutConstraint(item: newView, attribute: .CenterY, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 1, constant: 0)
self.view.addConstraint(x)
self.view.addConstraint(y)
}
If your LineChartView object is a subclass of UIView then this should work, and you should have a 50x50 object in the middle of your superview.
If you are going to be doing constraints like this in code you should consider using Apples Visual Formatting Language.
I want to have a button always in bottom and in left and right corner.
I want to do this with adding constraints to my button programatically.
My Code:
class LoginController: UIViewController {
#IBOutlet weak var LoginButton: UIButton!
override func loadView() {
super.loadView()
//Button Height Constraint
let constraintButtonPlayWidth = NSLayoutConstraint (item: self.LoginButton,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal,
toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1,
constant: 80)
self.view.addConstraint(constraintButtonPlayWidth)
//Button Right Constraint
let r = NSLayoutConstraint(item: self.LoginButton, attribute: .Right,
relatedBy: .Equal, toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0.0)
//Button Left Constraint
let l = NSLayoutConstraint(item: self.LoginButton, attribute: .Left,
relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 100.0)
//Button Bottom Constraint
let b = NSLayoutConstraint(item: self.LoginButton, attribute: .Bottom,
relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 100.0)
self.view.addConstraints([l,b,r])
When I run this code:
When i add Constraints in Designer:
and when i run the App it works
my Question: What is my mistake?
If you have a view in a storyboard with no constraints, the Interface Builder will generate some constraints automatically. These auto generated constraints will conflict with the code generated ones.
So, in my opinion you have four choices.
Generate Button in Code:
Create an Constraint in Interface Builder and remove them at build time by selecting constraint in Interface Builder and check "Remove at build time"
Remove auto generated Constraints in Code
Create Constraints in Interface Builder
Option 1 - Generate Button in Code
override func viewDidLoad()
{
super.viewDidLoad()
let button = UIButton()
button.setTitle("Login", forState: UIControlState.Normal)
button.backgroundColor = UIColor.redColor()
button.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(button)
let heightConstraint = NSLayoutConstraint(
item: button,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal,
toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1.0,
constant: 80
)
button.addConstraint(heightConstraint)
let leftConstraint = NSLayoutConstraint(
item: button,
attribute: NSLayoutAttribute.Leading,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Leading,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(leftConstraint)
let rightConstraint = NSLayoutConstraint(
item: button,
attribute: NSLayoutAttribute.Trailing,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Trailing,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(rightConstraint)
let topConstraint = NSLayoutConstraint(
item: button,
attribute: NSLayoutAttribute.Bottom,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Bottom,
multiplier: 1,
constant: 0
)
self.view.addConstraint(topConstraint)
}
Option 2 - Constraints in Code (with Constraint in IB removed at build time)
Create at least one constraint (e.g. a height constraint on the login button) and set the Remove at build time checkbox. After that you will get storyboard errors, you can fix them by adding more constraints (but i think it is not really necessary to fix the storyboard errors)
override func viewDidLoad()
{
super.viewDidLoad()
self.LoginButton.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal,
toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1.0,
constant: 80
)
self.LoginButton.addConstraint(heightConstraint)
let leftConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Leading,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Leading,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(leftConstraint)
let rightConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Trailing,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Trailing,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(rightConstraint)
let topConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Bottom,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Bottom,
multiplier: 1,
constant: 0
)
self.view.addConstraint(topConstraint)
}
Option 3 - Remove auto generated Constraints in Code
override func viewDidLoad()
{
super.viewDidLoad()
var removeConstraints : [NSLayoutConstraint] = []
for constraint in self.view.constraints
{
if constraint.firstItem === self.LoginButton
{
removeConstraints.append(constraint)
}
}
self.view.removeConstraints(removeConstraints)
self.LoginButton.removeConstraints(self.LoginButton.constraints)
self.LoginButton.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Height,
relatedBy: NSLayoutRelation.Equal,
toItem: nil,
attribute: NSLayoutAttribute.NotAnAttribute,
multiplier: 1.0,
constant: 80
)
self.LoginButton.addConstraint(heightConstraint)
let leftConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Leading,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Leading,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(leftConstraint)
let rightConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Trailing,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Trailing,
multiplier: 1.0,
constant: 0
)
self.view.addConstraint(rightConstraint)
let topConstraint = NSLayoutConstraint(
item: self.LoginButton,
attribute: NSLayoutAttribute.Bottom,
relatedBy: NSLayoutRelation.Equal,
toItem: self.view,
attribute: NSLayoutAttribute.Bottom,
multiplier: 1,
constant: 0
)
self.view.addConstraint(topConstraint)
}
Option 4 - Create in Interface Builder
Create Constraints in Interface Builder
If you want the button at the bottom, where you are setting the constraint, remove the 100 constant.
let b = NSLayoutConstraint(item: self.button, attribute: .Bottom,
relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
If you are targeting iOS 9 you can also add your constraints like this:
button.addConstraint(button.heightAnchor.constraintEqualToConstant(80))
self.view.addConstraint(self.view.leadingAnchor.constraintEqualToAnchor(button.leadingAnchor))
self.view.addConstraint(self.view.trailingAnchor.constraintEqualToAnchor(button.trailingAnchor))
self.view.addConstraint(self.view.bottomAnchor.constraintEqualToAnchor(button.bottomAnchor))
In my project I defined a xib and a ViewController that will contain the xib.
class FeedDetailViewController: UIViewController, FeedDetailDelegate {
var feedDetail: FeedDetail!
override func viewDidLoad() {
super.viewDidLoad()
feedDetail = (NSBundle.mainBundle().loadNibNamed("FeedDetail", owner: self, options: nil)[0] as? UIView)! as! FeedDetail
feedDetail.delegate = self;
self.view.addSubview(feedDetail)
self.adjustContraints()
}
func adjustContraints() {
feedDetail.sizeThatFits(self.view.frame.size)
var constraint = NSLayoutConstraint(item: feedDetail,
attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: feedDetail,
attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: feedDetail,
attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: feedDetail,
attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
view.addConstraint(constraint)
self.view.layoutIfNeeded()
}
What I want is simply the xib at "fullscreen", but xib borders are not "sticked" to the main view of the controller.
Border legend:
red: self.view
yellow: feedDetail
others: element inside feedDetail (test only)
Try to call this method before adding constraints.
feedDetail.setTranslatesAutoresizingMaskIntoConstraints(false)