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:
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.You are setting
translatesAutoresizingMaskIntoConstraints = false
onABSegment
itself. Don't do this. This tells Auto Layout that you will be specifying the size and location ofABSegment
using constraints, and you clearly are using aframe
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:
- I moved all of the setup of the label into a function called
setupLabel
. This allows it to be called by both initializers. - I added a computed property called
title
toABSegment
which allows you to change thetitle
at any time withmysegment.title = "new title"
. - I turned
init(withSegment:)
into a convenience init. It calls the standardinit(frame:)
and then sets thetitle
. It is not a common practice to usewithProperty
so I changed it. You'd create anABSegment
withvar segment = ABSegment(title: "some title")
. - I had
required init?(coder aDecoder: NSCoder)
callsetupLabel
so thatABSegment
can be used with views added in the Storyboard. - The overrides of
layoutSubviews
andupdateConstraints
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
Removing iPad Support from App
How to Detect When User Used Password Autofill on a Uitextfield
Show Data in Uipickerview Second Component Based on First Component Selection
How to Switch to Speaker Output When Bluetooth Headsets Are Connected
Replace iOS App Emoji with Twitter Open Source Twemoji
Sprite Kit Set Min. and Max. for Jump
Read Binary Qr Code with Avfoundation
Xamarin "The Executable Was Signed with Invalid Entitlements"
Collectionview Duplicate Cell When Loading More Data
How to Send a Uilongpressgesture Programmatically
Multiple Uialertcontrollers in iOS
How to Add a Custom Separator to Uitableviewcell
How to Change Uibutton Image After Clicking in Swift
How to Access Extension of Uicolor in Swift
Position a Subview on the Edge of a Circular Shaped View