let imageView = UIImageView(image: UIImage(named: "Loading"))
imageView.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
imageView.center = self.view.center
self.view.addSubview(imageView)
let xConstraint = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
let verticalSpace = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 100)
NSLayoutConstraint.activate([xConstraint, verticalSpace])
self.rotate(imageView: imageView, aCircleTime: 1)
let titleLabel = UILabel()
titleLabel.text = "Loading picker route"
titleLabel.textAlignment = .center
self.view.addSubview(imageView)
NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: self.view.frame.size.width).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 44).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: imageView , attribute: .centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: imageView, attribute: .bottom, multiplier: 1, constant: 100).isActive = true
Crash at last two lines with below report
Terminating app due to uncaught exception 'NSGenericException',
reason: 'Unable to activate constraint with anchors
<NSLayoutYAxisAnchor:0x2839a8540 "UILabel:0x115d12580.top"> and
<NSLayoutYAxisAnchor:0x2839fc000 "UIImageView:0x115d10730.bottom">
because they have no common ancestor. Does the constraint or its
anchors reference items in different view hierarchies? That's
illegal.'
You need to add the the label
titleLabel.textAlignment = .center
self.view.addSubview(titleLabel)
plus these 2 lines
imageView.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
Edit:
let imageView = UIImageView(image: UIImage(named: "Loading"))
imageView.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
imageView.center = self.view.center
self.view.addSubview(imageView)
let xConstraint = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
let verticalSpace = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 100)
let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
NSLayoutConstraint.activate([xConstraint, verticalSpace,width,height])
self.rotate(imageView: imageView, aCircleTime: 1)
let titleLabel = UILabel()
titleLabel.text = "Loading picker route"
titleLabel.textAlignment = .center
self.view.addSubview(titleLabel)
imageView.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: self.view.frame.size.width).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 44).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: imageView , attribute: .centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: imageView, attribute: .bottom, multiplier: 1, constant: 100).isActive = true
Related
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)
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.
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 :)
I'm using a the pod SDCAlertView, I need to add an imageView + a textField to my content view, however I am having trouble with my constraints, below is my code.
let imageView = UIImageView(frame: CGRectMake(0, 0, 100, 100))
imageView.image = UIImage(named: "kalafina")
imageView.contentMode = .ScaleAspectFill
let alert = AlertController(title: "Testing", message: "1234")
imageView.translatesAutoresizingMaskIntoConstraints = false
alert.contentView.addSubview(imageView)
let imageHeightConstraint = NSLayoutConstraint(item: imageView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100)
let imageWidthConstraint = NSLayoutConstraint(item: imageView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100)
let imageCenterXConstraint = NSLayoutConstraint(item: imageView, attribute: .CenterX, relatedBy: .Equal, toItem: alert.contentView, attribute: .CenterX, multiplier: 1.0, constant: 0.0)
let imageTopConstraint = NSLayoutConstraint(item: imageView, attribute: .Top, relatedBy: .Equal, toItem: alert.contentView, attribute: .Top, multiplier: 1.0, constant: 0)
let imageBottomConstraint = NSLayoutConstraint(item: imageView, attribute: .Bottom, relatedBy: .Equal, toItem: alert.contentView, attribute: .Bottom, multiplier: 1.0, constant: 0)
alert.view.addConstraint(imageTopConstraint)
alert.view.addConstraint(imageBottomConstraint)
alert.view.addConstraint(imageHeightConstraint)
alert.view.addConstraint(imageWidthConstraint)
alert.view.addConstraint(imageCenterXConstraint)
alert.addAction(AlertAction(title: "Cancel", style: .Preferred))
alert.addAction(AlertAction(title: "Ok", style: .Default, handler: { action in
print("Sending")
}))
alert.present()
This is my result
You are adding your constraints to alert.view, but you should be adding them to alert.contentView. If you do that everything works as expected.
Within UIView I have a method presentView():
public func presentView() {
UIApplication.sharedApplication().delegate?.window??.addSubview(self)
let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.backgroundColor = UIColor.yellowColor()
addSubview(blurEffectView)
let topConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
self.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
print("newframe: \(blurEffectView.frame)")
}
but sth is wrong because this is the output on console:
newframe: (0.0, 0.0, 0.0, 0.0)
and result is:
Remember about:
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
and then:
let topConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: blurEffectView, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1, constant: 0)
addSubview(blurEffectView)
addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
layoutIfNeeded()