Message bubble constraints with swift - ios

I know this is a hard problem to debug. I will try to explain, you can ask question from comments section.
I want to use message bubbles in my app. I wrote some code for constraints, but it is not working well.
How can i put the left edge of blue bubble to red line?
Here is my code:
When tableview cell loads this method is running:
private func setup() {
bubbleImageView = UIImageView(image: bubbleImage.incoming, highlightedImage: bubbleImage.incomingHighlighed)
bubbleImageView.userInteractionEnabled = true
messageLabel = UILabel(frame: CGRectZero)
messageLabel.font = UIFont.systemFontOfSize(15)
messageLabel.numberOfLines = 0
messageLabel.userInteractionEnabled = true
selectionStyle = .None
contentView.addSubview(bubbleImageView)
bubbleImageView.addSubview(messageLabel)
messageLabel.translatesAutoresizingMaskIntoConstraints = false
bubbleImageView.translatesAutoresizingMaskIntoConstraints = false
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .Left, relatedBy: .Equal, toItem: contentView, attribute: .Left, multiplier: 1, constant: 10))
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1, constant: 4.5))
bubbleImageView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .Width, relatedBy: .Equal, toItem: messageLabel, attribute: .Width, multiplier: 1, constant: 30))
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1, constant: -4.5))
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLabel, attribute: .CenterX, relatedBy: .Equal, toItem: bubbleImageView, attribute: .CenterX, multiplier: 1, constant: -2))
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLabel, attribute: .CenterY, relatedBy: .Equal, toItem: bubbleImageView, attribute: .CenterY, multiplier: 1, constant: -0.5))
messageLabel.preferredMaxLayoutWidth = 218
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLabel, attribute: .Height, relatedBy: .Equal, toItem: bubbleImageView, attribute: .Height, multiplier: 1, constant: -15))
}
As you can see i am creating bubble background and label for text.
And second method:
func setCell(message:Message) {
messageLabel.text="testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest"
var layoutAttribute: NSLayoutAttribute
var layoutConstant: CGFloat
if message.incoming {
bubbleImageView.image=bgImage.incoming
messageLabel.textColor = UIColor.blackColor()
layoutAttribute = .Left
layoutConstant = 10
}else{
if message.isSent == 1 {
bubbleImageView.image = bgImage.outgoing
}
if message.isSent == 0 {
bubbleImageView.image = bgImage.notYetSent
}
messageLabel.textColor = UIColor.whiteColor()
layoutAttribute = .Right
layoutConstant = -10
}
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: layoutAttribute, relatedBy: .Equal, toItem: contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
}
What is the problem with my code? It is working well for incoming messages (gray bubble) and not working well for outgoing messages (blue bubble)

I get it. You have to add a constraint that doesnt allows the bubble to exceed the max width. So you have to add a constraint like that:
let widthConstraint = NSLayoutConstraint(item: youritem, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.LessThanOrEqual,
toItem: self.youItem.superview, attribute: NSLayoutAttribute.Width,
multiplier: 1.0, constant: 100)

Related

View hierarchy is not prepared for the constraint: Unable to Find the Issue

The Following are the constraints that am using.
<NSLayoutConstraint:0x7fcfdd405bc0 UILabel:0x7fcfdd405780'ACTIVITY'.centerY == UIView:0x7fcfdb677b60.centerY>The view hierarchy is not prepared for the constraint:
footer!.frame = CGRectMake(0, 0, tableView.frame.size.width, FOOTER_HEIGHT)
let activityLabel = UILabel()
activityLabel.text = "SomeText"
activityLabel.translatesAutoresizingMaskIntoConstraints = false
let CenterConstraint = NSLayoutConstraint(item: activityLabel, attribute: .CenterX, relatedBy: .Equal, toItem: footerView, attribute: .CenterX, multiplier: 1, constant: 0)
let CenterConstraint = NSLayoutConstraint(item: activityLabel, attribute: .CenterY, relatedBy: .Equal, toItem: footerView, attribute: .CenterY, multiplier: 1, constant: 0)
footer!.addConstraints([xxCenterConstraint,yyCenterConstraint])
footer!.addSubview(activityLabel)
let notificationLabel = UILabel()
notificationLabel.text = "9"
notificationLabel.textAlignment = .Center
notificationLabel.backgroundColor = customBlueColor
footerView!.addSubview(notificationLabel)
notificationLabel.translatesAutoresizingMaskIntoConstraints = false
let width = NSLayoutConstraint(item: notificationLabel, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: NOTIFICATION_LABEL_HEIGHT)
let height = NSLayoutConstraint(item: notificationLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: NOTIFICATION_LABEL_HEIGHT)
let yCenterConstraint = NSLayoutConstraint(item: notificationLabel, attribute: .CenterY, relatedBy: .Equal, toItem: footerView, attribute: .CenterY, multiplier: 1, constant: 0)
let leadingConstraint1 = NSLayoutConstraint(item: activityLabel, attribute: .Trailing, relatedBy: .Equal, toItem: notificationLabel, attribute: .Leading, multiplier: 1, constant:-LEADING_SPACE)
footer!.addConstraints([width,height,yCenterConstraint,leadingConstraint1])
notificationLabel.layer.cornerRadius = NOTIFICATION_LABEL_HEIGHT/2
notificationLabel.clipsToBounds = true
You can't add constraints before the views are part of the same view hierarchy. Move the addSubview line before the addConstraints line.

UIButton Constraint Failure, but works with UILabel

I am trying to add a button pragmatically to a UIView. This code will work with a UI label, but when using it with a button, the constraints fail. How can I make this work? Thanks.
let homeButton = UIButton(frame: CGRectZero)
homeButton.setTitle("Home", forState: .Normal)
homeButton.titleLabel!.textAlignment = NSTextAlignment.Center
homeButton.titleLabel!.textColor = UIColor.whiteColor()
homeButton.titleLabel!.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(homeButton)
let buttonWidthConstraint = NSLayoutConstraint(item: homeButton, attribute: .Width, relatedBy: .Equal, toItem: self.containerView, attribute: .Width, multiplier: 0.5, constant: 0)
containerView.addConstraint(buttonWidthConstraint)
let buttonHeightConstraint = NSLayoutConstraint(item: homeButton, attribute: .Height, relatedBy: .Equal, toItem: self.containerView, attribute: .Height, multiplier: 0.5,constant: 0)
containerView.addConstraint(buttonHeightConstraint)
let buttonXConstraint = NSLayoutConstraint(item: homeButton, attribute: .CenterX, relatedBy: .Equal, toItem: self.containerView, attribute: .CenterX, multiplier: 1, constant: 0)
let buttonYConstraint = NSLayoutConstraint(item: homeButton, attribute: .CenterY, relatedBy: .Equal, toItem: self.containerView, attribute: .CenterY, multiplier: 1, constant: 0)
containerView.addConstraint(buttonXConstraint)
containerView.addConstraint(buttonYConstraint)
you should use homeButton.translatesAutoresizingMaskIntoConstraints = false instead of homeButton.titleLabel!.translatesAutoresizingMaskIntoConstraints = false.
because you should disable autoresizingmask for button not for button's titleLabel!!!
Hope this will help :)

Layout Constraints Added Programmatically to UITableViewCell

I am attempting to reproduce the constraints in this screenshot, which are applied to a static UITableViewCell:
Here is the code I'm using to try to do this:
#IBOutlet weak var cellTest: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
cellTest.backgroundColor = UIColor.yellowColor()
let vw = UIView()
vw.backgroundColor = UIColor.greenColor()
cellTest.contentView.addSubview(vw)
cellTest.contentView.translatesAutoresizingMaskIntoConstraints = false
vw.translatesAutoresizingMaskIntoConstraints = false
let constraintWidth = NSLayoutConstraint(item: vw, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 400)
let constraintHeight = NSLayoutConstraint(item: vw, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 150)
let constraintCentreX = NSLayoutConstraint(item: vw, attribute: .CenterX, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterX, multiplier: 1, constant: 0)
let constraintCentreY = NSLayoutConstraint(item: vw, attribute: .CenterY, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterY, multiplier: 1, constant: 0)
cellTest.contentView.addConstraints([constraintWidth, constraintHeight, constraintCentreX, constraintCentreY ])
}
However, below is the unexpected output, with the view in the top left instead of centred. Any help is much appreciated as I've spent quite some time trying to figure this out:
I needed to add constraints to the cell's contentView, as well. These are added to the cell itself.
Code and screenshot below.
#IBOutlet weak var cellTest: UITableViewCell!
override func viewDidLoad() {
super.viewDidLoad()
cellTest.backgroundColor = UIColor.yellowColor()
let vw = UIView()
vw.backgroundColor = UIColor.greenColor()
cellTest.contentView.addSubview(vw)
cellTest.contentView.translatesAutoresizingMaskIntoConstraints = false
vw.translatesAutoresizingMaskIntoConstraints = false
let bottomConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: cellTest.contentView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: cellTest.contentView.superview!, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
cellTest.addConstraints([bottomConstraint, trailingConstraint, topConstraint, leadingConstraint])
let constraintWidth = NSLayoutConstraint(item: vw, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 200)
constraintWidth.priority = 1000
let constraintHeight = NSLayoutConstraint(item: vw, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 80)
constraintHeight.priority = 1000
let constraintCentreX = NSLayoutConstraint(item: vw, attribute: .CenterX, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterX, multiplier: 1, constant: 0)
constraintCentreX.priority = 1000
let constraintCentreY = NSLayoutConstraint(item: vw, attribute: .CenterY, relatedBy: .Equal, toItem: vw.superview!, attribute: .CenterY, multiplier: 1, constant: 0)
constraintCentreY.priority = 1000
cellTest.contentView.addConstraints([constraintWidth, constraintHeight, constraintCentreX, constraintCentreY ])
}

How best to optimize NSLayoutConstraint?

Colleagues,
I develop a custom keyboard. There was a problem with the speed of switching between types of keyboards (letters, numbers, special characters). This is due to the fact that each time the button is re-drawn. NSLayoutConstraint I set up as follows:
There is a class KeyboardViewController. He adds to his KeyboardView
let left = NSLayoutConstraint(item: self.keyboardView, attribute: .Left, relatedBy: .Equal,
toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
let top = NSLayoutConstraint(item: self.keyboardView, attribute: .Top, relatedBy: .Equal,
toItem: placeForSuggestion!, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
let right = NSLayoutConstraint(item: self.keyboardView, attribute: .Right, relatedBy: .Equal,
toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0.0)
let bottom = NSLayoutConstraint(item: self.keyboardView, attribute: .Bottom, relatedBy: .Equal,
toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
let height = NSLayoutConstraint(item: self.keyboardView, attribute: .Height, relatedBy: .Equal,
toItem: self.view, attribute: .Height, multiplier: 1.0, constant: 216)
left.priority = 999
right.priority = 999
bottom.priority = 999
top.priority = 999
height.priority = 999
self.view.addConstraints([left, right, top, bottom, height])
In the class KeyboardView, buttons are added as follows:
super.updateConstraints()
if !layoutConstrained {
var lastRowView: UIView? = nil
for (rowIndex, keyRow) in keyRows.enumerate() {
var lastKeyView: UIView? = nil
for (keyIndex, key) in keyRow.enumerate() {
var relativeWidth: CGFloat = 0.0;
switch key.type! {
case .ModeChange:
relativeWidth = 0.92/8
case .KeyboardChange:
relativeWidth = 0.92/8
case .Space:
relativeWidth = 3.92/8
case .Return:
relativeWidth = 1.84/8
default:
relativeWidth = 0.0
}
key.translatesAutoresizingMaskIntoConstraints = false
if let lastView = lastKeyView {
let left: NSLayoutConstraint!
if (key.keyCap == "Z" || (key.keyCap == "backspace" && keyRow[keyIndex - 1].keyCap == "M")) {
left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: lastView, attribute: .Right, multiplier: 1.0, constant: englishMZSpace)
} else {
left = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: lastView, attribute: .Right, multiplier: 1.0, constant: distanceBetweenKeys)
}
let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy: .Equal,
toItem: lastView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let bottom = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
toItem: lastView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
var width: NSLayoutConstraint?
if relativeWidth == 0.0 {
width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
toItem: lastView, attribute: .Width, multiplier: 1.0, constant: 0.0)
} else {
width = NSLayoutConstraint(item: key, attribute: .Width, relatedBy: .Equal,
toItem: self, attribute: .Width, multiplier: relativeWidth, constant: 0.0)
}
self.addConstraints([left, top, bottom, width!])
} else {
let leftEdge: NSLayoutConstraint
if key.keyCap == "A" {
leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: self, attribute: .Left, multiplier: 1.0, constant: englishALSpace)
} else {
leftEdge = NSLayoutConstraint(item: key, attribute: .Left, relatedBy: .Equal,
toItem: self, attribute: .Left, multiplier: 1.0, constant: leftRightSpace)
}
self.addConstraint(leftEdge)
if let lastRow = lastRowView {
let top = NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
toItem: lastRow, attribute: .Bottom, multiplier: 1.0, constant: rowTopInset)
let height = NSLayoutConstraint(item: key, attribute: .Height, relatedBy: .Equal,
toItem: lastRow, attribute: .Height, multiplier: 1.0, constant: 0.0)
self.addConstraints([top, height])
} else {
let topEdge = NSLayoutConstraint(item: key, attribute: .Top, relatedBy:.Equal,
toItem: self, attribute: .Top, multiplier: 1.0, constant: rowTopInset)
self.addConstraint(topEdge)
}
if rowIndex == keyRows.count - 1 {
let bottomEdge = NSLayoutConstraint(item: key, attribute: .Bottom, relatedBy: .Equal,
toItem: self, attribute: .Bottom, multiplier: 1.0, constant: -rowBottomInset)
self.addConstraint(bottomEdge)
}
lastRowView = key
}
if keyIndex == keyRow.count - 1 {
let rightEdge: NSLayoutConstraint
if key.keyCap == "L" {
rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
toItem: self, attribute: .Right, multiplier: 1.0, constant: -englishALSpace)
} else {
rightEdge = NSLayoutConstraint(item: key, attribute: .Right, relatedBy: .Equal,
toItem: self, attribute: .Right, multiplier: 1.0, constant: -leftRightSpace)
}
self.addConstraint(rightEdge)
}
lastKeyView = key
}
}
layoutConstrained = true
}
I see 2 variants of optimization:
After the first run to cache all NSLayoutConstraint
Use CGRectMake instead NSLayoutConstraint
You may be able to offer more relevant options?
In this video I try to switch keyboard and print quickly https://yadi.sk/i/36YxEwgtmHJVd
It seems pretty fast to me in the video.
However, instead of re-creating the layout constraints every time I would recommend to create each keyboard type once, and then just switch between the existing keyboards. Regarding the small views that shouldn't be a memory issue, and it's a lot better than recreating and deleting constraints all the time.
Alternatively, if the key amount stays (almost) the same, you could just change the constraint's values and even animate the change of key positions for a maybe nice effect.

Swift NSlayoutConstraint

I have a question... I am really not understand something.
I have a UIView Class which only create a UITextLabel.. I'm trying to add instances from this class to my Viewcontroller. This is how my UIViewClass look like:
class PostLineItem: UIView {
var labelText : String!
var labelHeader : String!
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
//tlb.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("required public")
}
private func timeLineBlock() -> UIView{
let viewNew = UIView()
viewNew.setTranslatesAutoresizingMaskIntoConstraints(false)
let titleLabel = UILabel()
titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
titleLabel.font = UIFont(name: "ArialMT", size: 20)
titleLabel.textColor = UIColor.blackColor()
titleLabel.text = labelHeader
titleLabel.numberOfLines = 0
viewNew.addSubview(titleLabel)
titleLabel.backgroundColor = UIColor.redColor()
/* IF I NOT COMMENT THIS PART INSTANCE OF THIS CLASS IS NOT SHOWING UP.
viewNew.addConstraints([
NSLayoutConstraint(item: titleLabel, attribute: .Width, relatedBy: .Equal, toItem: viewNew, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Left, relatedBy: .Equal, toItem: viewNew, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Top, relatedBy: .Equal, toItem: viewNew, attribute: .Top, multiplier: 1.0, constant: 0)
])
*/
viewNew.backgroundColor = UIColor.greenColor()
return viewNew
}
}
And this is my viewController class part where i try to instantiate the PostLineItem instances..
let guideView = UIView()
guideView.setTranslatesAutoresizingMaskIntoConstraints(false)
guideView.backgroundColor = UIColor.blackColor()
scrollView.addSubview(guideView)
scrollView.addConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 50),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: -30),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:10)
])
guideView.backgroundColor = UIColor.blackColor()
var viewFromAbove = guideView
for post in 1...70 {
let v = PostLineItem(labelText: "Tst", labelHeader: "Tst2")
scrollView.addSubview(v)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 15),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 400)
])
viewFromAbove = v
}
scrollView.addConstraints([
NSLayoutConstraint(item: viewFromAbove, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: -10)
])
As you can see, first of all i create a guidview for the first PostLineItem and then adding the new instances and the constraints.. So..
If i do it this way the instances of the PostLineItem class will be at the same places and hides each others... I think, the NSLAyoutConstaint not effect.
But, as you can see at the commented part of the code, if i create a simple UILabel the constraints work fine, and all of the UILabel instances will be under each others..
UPDATE:
after i adding all of written in the answer it's look like this.. :(
That little red rect is my PostLineItem instance.. :(
UPDATED - all code.
I'm thinking you might be adding the constraints to the wrong views. For instance, the guideView height constraint should be added to the guideView, and not the scrollView. I would suggest instead you use the new way of activating constraints. Instead of adding them to the views, you just call the activateConstraints class method on NSLayoutConstraint:
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 24),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:4)
])
and
NSLayoutConstraints.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 5),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
])
Also, you are missing a constraint for the height of your PostLineItem, something like:
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:10)
In your PostLineItem init, you need to add constraints for the timeLineBlock:
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
Here is my version. I'm getting much better results. Take a look... Note, I set up my scrollView entirely in Interface Builder and just added an outlet called scrollView that points to the contentView contained by my scrollView. That shouldn't matter. Everything else is as you implemented.
class PostLineItem: UIView {
var labelText : String!
var labelHeader : String!
init(labelText: String , labelHeader: String) {
super.init(frame: CGRect.zeroRect)
self.labelText = labelText
self.labelHeader = labelHeader
let tlb = timeLineBlock()
self.addSubview(tlb)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: tlb, attribute: .Height, relatedBy: .Equal, toItem: self, attribute: .Height, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Width, relatedBy: .Equal, toItem: self, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: tlb, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)
])
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("required public")
}
private func timeLineBlock() -> UIView{
let viewNew = UIView()
viewNew.setTranslatesAutoresizingMaskIntoConstraints(false)
let titleLabel = UILabel()
titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
titleLabel.font = UIFont(name: "ArialMT", size: 20)
titleLabel.textColor = UIColor.blackColor()
titleLabel.text = labelHeader
titleLabel.numberOfLines = 0
viewNew.addSubview(titleLabel)
titleLabel.backgroundColor = UIColor.redColor()
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: titleLabel, attribute: .Width, relatedBy: .Equal, toItem: viewNew, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Left, relatedBy: .Equal, toItem: viewNew, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: titleLabel, attribute: .Top, relatedBy: .Equal, toItem: viewNew, attribute: .Top, multiplier: 1.0, constant: 0)
])
viewNew.backgroundColor = UIColor.greenColor()
return viewNew
}
}
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let guideView = UIView()
guideView.setTranslatesAutoresizingMaskIntoConstraints(false)
guideView.backgroundColor = UIColor.blackColor()
scrollView.addSubview(guideView)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: guideView, attribute: .Top, relatedBy: .Equal, toItem: scrollView, attribute: .Top, multiplier: 1.0, constant: 24),
NSLayoutConstraint(item: guideView, attribute: .Left, relatedBy: .Equal, toItem: scrollView, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: guideView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:4)
])
guideView.backgroundColor = UIColor.blackColor()
var viewFromAbove = guideView
for post in 1...70 {
let v = PostLineItem(labelText: "Tst", labelHeader: "Tst2")
//let v = UILabel(frame: CGRectMake(0, 0, 10, 10))
//v.text = "Tst Now with this its working, and the constraint is fine."
v.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.addSubview(v)
NSLayoutConstraint.activateConstraints([
NSLayoutConstraint(item: v, attribute: .Top, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Bottom, multiplier: 1.0, constant: 5),
NSLayoutConstraint(item: v, attribute: .Left, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Left, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Width, relatedBy: .Equal, toItem: viewFromAbove, attribute: .Width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: v, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant:30)
])
viewFromAbove = v
}
}
}

Resources