Programmatically Added Constraint Not Working

Programmatically Added Constraint Not Working

set translatesAutoresizingMaskIntoConstraints = false to any view you are settings constraints programatically.

from the apple doc:
translatesAutoresizingMaskIntoConstraints

If you want to use Auto Layout to dynamically calculate the size and position of your view, you must set this property to false, and then provide a non ambiguous, nonconflicting set of constraints for the view.

Adding Constraint Programmatically Does Not Work

Your implementation logic working for me.

  • Left image show implementation without height constraint.
  • Right image show button pressed with height constraint.


In function viewDidLoad

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
scrollView.isScrollEnabled = true
scrollView.bounces = false
scrollView.alwaysBounceVertical = true
imageView.image = UIImage(color: .lightGray)

navigationItem.rightBarButtonItem = barButtonItem
view.addSubview(scrollView)
scrollView.addSubview(imageView)

scrollView.translatesAutoresizingMaskIntoConstraints = false
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
imageView.leftAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leftAnchor),
imageView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
imageView.rightAnchor.constraint(equalTo: scrollView.contentLayoutGuide.rightAnchor),
imageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
}

In function buttonPressed

@objc func buttonPressed() {
navigationItem.rightBarButtonItem = nil
UIView.animate(withDuration: 1) {
NSLayoutConstraint.activate([
self.imageView.heightAnchor.constraint(equalTo: self.scrollView.heightAnchor)
])
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}

UIImage util Create UIImage with solid color in Swift

fileprivate extension UIImage {
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else { return nil }
self.init(cgImage: cgImage)
}
}

Swift programmatically-added constraints dont work

Remove width anchor. You should not care about width (and you don't really know it), use trailingAnchor instead:

label.trailingAnchor.constraint(equalTo: lv.trailingAnchor, constant: -4).isActive = true

Remove heightAnchor, instead let system calculate the height for you:

label.setContentHuggingPriority(.required, for: .vertical)
label.setContentCompressionResistancePriority(.required, for: .vertical)

That should be all needed.

However, as a side note, instead of creating a constraint to previous label, you could just use a UIStackView.

Programmatic Constraints not working as expected

The main problems I see with your code:

  1. You are adding and removing constraints every time updateConstraints is called. You only need to set up the constraints once when you create your view.

  2. You are setting translatesAutoresizingMaskIntoConstraints = false on ABSegment itself. Don't do this. This tells Auto Layout that you will be specifying the size and location of ABSegment using constraints, and you clearly are using a frame for this purpose.


Here is the refactored code:

class ABSegment: UIView {

let titleLabel = UILabel()

// Computed property to allow title to be changed
var title: String {
set {
titleLabel.text = newValue
}
get {
return titleLabel.text ?? ""
}
}

override init(frame: CGRect) {
super.init(frame: frame)

setupLabel(title: "")
}

convenience init(title: String) {

self.init(frame: CGRect.zero)

self.title = title
}

// This init is called if your view is
// set up in the Storyboard
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)

setupLabel(title: "")
}

func setupLabel(title: String) {

titleLabel.text = title

titleLabel.textAlignment = .center

addSubview(titleLabel)

backgroundColor = UIColor.blue

titleLabel.translatesAutoresizingMaskIntoConstraints = false

let centerX = NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)

let centerY = NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)

let width = NSLayoutConstraint(item: titleLabel, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)

let height = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: 0)

NSLayoutConstraint.activate([centerX, centerY, width, height])
}

override func layoutSubviews() {
super.layoutSubviews()
logFrames()
}

func logFrames() {
print("self.frame is \(frame)")
print("titleLabel.frame is \(titleLabel.frame)")
}

override func updateConstraints() {
super.updateConstraints()
logFrames()
}

}

Notes:

  1. I moved all of the setup of the label into a function called setupLabel. This allows it to be called by both initializers.
  2. I added a computed property called title to ABSegment which allows you to change the title at any time with mysegment.title = "new title".
  3. I turned init(withSegment:) into a convenience init. It calls the standard init(frame:) and then sets the title. It is not a common practice to use withProperty so I changed it. You'd create an ABSegment with var segment = ABSegment(title: "some title").
  4. I had required init?(coder aDecoder: NSCoder) call setupLabel so that ABSegment can be used with views added in the Storyboard.
  5. The overrides of layoutSubviews and updateConstraints were left in to log the frames. That is all that they do now.

Programmatically adding constraints in Swift does not work

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.

UITextField not working with add constraints programmatically

I just run your code, it looks like scrollMainView is not visible in the views' hierarchy. Just change the constraints. Here is the code:

func addScrollMainView() {
scrollMainView = UIView()
scrollView.addSubview(scrollMainView)
scrollMainView.translatesAutoresizingMaskIntoConstraints = false
let leadingConst = scrollMainView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0)
let trailingConst = scrollMainView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0)
let topConst = scrollMainView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0)
let bottomConst = scrollMainView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
NSLayoutConstraint.activate([topConst,leadingConst,trailingConst,bottomConst])
emailFieldView()
}

BTW, It is not related to your question, but it is better to create bg at the beginning. Just use the code below:

func setDesign(){
setBackgroundImage()
setNavegationBar()
addScrollView()
}

Trailing constraint not applying when programmatically adding UIConstraints

Your constraint is being applied but as you have set it to 16 it is going 16 points past the trailing edge of the view. You therefore should use a negative value for the constant instead.



Related Topics



Leave a reply



Submit