How can I set aspect ratio constraints programmatically in iOS?
Like this. Try once.
[self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.yourview addConstraint:[NSLayoutConstraint
constraintWithItem:self.yourview
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.yourview
attribute:NSLayoutAttributeWidth
multiplier:(self.yourview.frame.size.height / self.yourview.frame.size.width)
constant:0]];
or in the place of (self.yourview.frame.size.height / self.yourview.frame.size.width)
you can use any float value.
Thanks.
Swift 3.0 -
self.yourview!.translatesAutoresizingMaskIntoConstraints = false
self.yourview!.addConstraint(NSLayoutConstraint(item: self.yourview!,
attribute: NSLayoutAttribute.height,
relatedBy: NSLayoutRelation.equal,
toItem: self.yourview!,
attribute: NSLayoutAttribute.width,
multiplier: self.yourview.frame.size.height / self.yourview.frame.size.width,
constant: 0))
Swift change aspect ratio constraint programmatically
Your initial constraints should look like this.
NSLayoutConstraint.activate([
foo.leadingAnchor.constraint(equalTo: superView.leadingAnchor),
foo.trailingAnchor.constraint(equalTo: superView.trailingAnchor),
foo.topAnchor.constraint(equalTo: superView.topAnchor)
])
let collapsedConstraint = foo.heightAnchor.constraint(equalTo: foo.widthAnchor, multiplier: 9/16)
let expandedConstraint = foo.bottomAnchor.constraint(equalTo: superView.bottomAnchor)
collapsedConstraint.isActive = collapsed
expandedConstraint.isActive = !collapsed
And the method that is triggered should change the constraints like this.
@objc func tapAction() {
collapsedConstraint.isActive = collapsed
expandedConstraint.isActive = !collapsed
superView.layoutIfNeeded()
}
1:1 width:height constraint to UIButton programmatically
Try this
myButton.addConstraint(NSLayoutConstraint(item: myButton, attribute: .height, relatedBy: .equal, toItem: myButton, attribute: .width, multiplier: 1, constant: 0))
Change Aspect Ratio constraint value programmatically
You can use following approach
Give two constraints. One for aspect ratio and another for height.
Make the two active alternatively like
constOptions_Aspect.isActive = false
constOptions_Height.isActive = true
You can give height zero, in height constant.
How to change aspectRatio of IBOutlet for a view programmatically?
Changing the aspect ratio means changing the multiplier of the constraint which is a read-only so you need to deactivate that constraint and create a new 1 with a new multiplier
let newCon = contentViewAspectRatio.addConstraintWithMul(0.3)
parentViewOfConstraint.removeConstraint(contentViewAspectRatio)
parentViewOfConstraint.addConstraint(newCon)
view.layoutIfNeeded()
contentViewAspectRatio = newCon
extension NSLayoutConstraint {
func addConstraintWithMul(_ multiplier: CGFloat) -> NSLayoutConstraint {
return NSLayoutConstraint(item: self.firstItem!, attribute: self.firstAttribute, relatedBy: self.relation, toItem: self.secondItem, attribute: self.secondAttribute, multiplier: multiplier, constant: self.constant)
}
}
Another option is to create 2 constraints with 2 different aspects and play with their active / priority state in case you have a limited and know number of aspects
Set UIImageView AspectRatio constraint programmatically in swift 3
You can change constraint programmatically in swift 3
let aspectRatioConstraint = NSLayoutConstraint(item: self.YourImageObj,attribute: .height,relatedBy: .equal,toItem: self.YourImageObj,attribute: .width,multiplier: (2.0 / 1.0),constant: 0)
self.YourImageObj.addConstraint(aspectRatioConstraint)
iOS programmatically aspect ratio constraint gets broken in UITableviewcell
I believe you must reduce the priority on your aspect-ratio constraint to avoid the broken constraint messages.
And, I think you're not-quite-correct about nn.5
values working.
For example... With a 420:360
ratio:
setting the width of the view to 59
results in an auto-layout height calculation of
59.0 * 360.0 / 420.0 == 50.571428571428569
Auto-layout is not going to give you an actual view height of 50.571428571428569
... it's going to round it to the nearest .5
which is 50.5
and that is less than requested so you get the error.
With:
59.4 * 360.0 / 420.0 == 50.914285714285718
it rounds to 51
, which is greater than requested, and you do not get the error.
A few more examples:
58.5 * 360.0 / 420.0 == 50.142857142857146 // rounds down -- error
58.4 * 360.0 / 420.0 == 50.057142857142857 // rounds down -- error
58.3 * 360.0 / 420.0 == 49.971428571428568 // rounds up -- NO ERROR
Changing your aspect-ratio constraint to Priority: 999
gives the same sizing results (rounds to the nearest .5
) but does not throw the broken constraint error.
Since you will get the same actual size, changing the priority will simply allow auto-layout to "do the right thing" and shouldn't have any other effect on your layout.
AutoLayout constraints to fit view inside rectangle, preserving a certain aspect ratio (programmatically)
OK - here is one way to do it.
Take the "native" size of your subview, calculate the "aspect fit" ratio - that is, the ratio that will fit the width or height to the superview, and scale the other dimension appropriately.
Then, use centerXAnchor
and centerYAnchor
to position the subview, and widthAnchor
and heightAnchor
to size it.
Note: if you're trying to place an image, calculate the aspect fit size from the image size, put the image in an image view, set the image view scale mode to fill
, and finally apply the constraints to the image view.
You should be able to run this example as-is. Just play around with the "native" size values at the top to see how it fits the subview into the superview.
public class AspectFitViewController : UIViewController {
// "native" size for the holderView
let hViewWidth: CGFloat = 700.0
let hViewHeight: CGFloat = 200.0
let topView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.blue
return v
}()
let holderView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.cyan
return v
}()
public override func viewDidLoad() {
super.viewDidLoad()
view.bounds = CGRect(x: 0, y: 0, width: 400, height: 600)
view.backgroundColor = .yellow
// add topView
view.addSubview(topView)
// pin topView to leading / top / trailing
topView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true
topView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
topView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true
// explicit height for topView
topView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true
// add holderView to topView
topView.addSubview(holderView)
// center X and Y
holderView.centerXAnchor.constraint(equalTo: topView.centerXAnchor, constant: 0.0).isActive = true
holderView.centerYAnchor.constraint(equalTo: topView.centerYAnchor, constant: 0.0).isActive = true
// holderView's width and height will be calculated in viewDidAppear
// after topView has been laid-out by the auto-layout engine
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let aspectWidth = topView.bounds.size.width / hViewWidth
let aspectHeight = topView.bounds.size.height / hViewHeight
let aspectFit = min(aspectWidth, aspectHeight)
let newWidth = hViewWidth * aspectFit
let newHeight = hViewHeight * aspectFit
holderView.widthAnchor.constraint(equalToConstant: newWidth).isActive = true
holderView.heightAnchor.constraint(equalToConstant: newHeight).isActive = true
}
}
Edit:
After clarification... this can be accomplished by constraints only. The key is that "Priority 1000" top
and leading
constraints must be .greaterThanOrEqual
to zero, and the bottom
and trailing
constraints must be .lessThanOrEqual
to zero.
public class AspectFitViewController : UIViewController {
// "native" size for the holderView
let hViewWidth: CGFloat = 700.0
let hViewHeight: CGFloat = 200.0
let topView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.blue
return v
}()
let holderView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor.cyan
return v
}()
public override func viewDidLoad() {
super.viewDidLoad()
view.bounds = CGRect(x: 0, y: 0, width: 400, height: 600)
view.backgroundColor = .yellow
// add topView
view.addSubview(topView)
// pin topView to leading / top / trailing
topView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true
topView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true
topView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true
// explicit height for topView
topView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true
// add holderView to topView
topView.addSubview(holderView)
// center X and Y
holderView.centerXAnchor.constraint(equalTo: topView.centerXAnchor, constant: 0.0).isActive = true
holderView.centerYAnchor.constraint(equalTo: topView.centerYAnchor, constant: 0.0).isActive = true
// aspect ratio size
holderView.widthAnchor.constraint(equalTo: holderView.heightAnchor, multiplier: hViewWidth / hViewHeight).isActive = true
// two constraints for each side...
// the .equal constraints need .defaultLow priority
// top and leading constraints must be .greaterThanOrEqual to 0
// bottom and trailing constraints must be .lessThanOrEqual to 0
let topA = NSLayoutConstraint(item: holderView, attribute: .top, relatedBy: .greaterThanOrEqual, toItem: topView, attribute: .top, multiplier: 1.0, constant: 0.0)
let topB = NSLayoutConstraint(item: holderView, attribute: .top, relatedBy: .equal, toItem: topView, attribute: .top, multiplier: 1.0, constant: 0.0)
let bottomA = NSLayoutConstraint(item: holderView, attribute: .bottom, relatedBy: .lessThanOrEqual, toItem: topView, attribute: .bottom, multiplier: 1.0, constant: 0.0)
let bottomB = NSLayoutConstraint(item: holderView, attribute: .bottom, relatedBy: .equal, toItem: topView, attribute: .bottom, multiplier: 1.0, constant: 0.0)
let leadingA = NSLayoutConstraint(item: holderView, attribute: .leading, relatedBy: .greaterThanOrEqual, toItem: topView, attribute: .leading, multiplier: 1.0, constant: 0.0)
let leadingB = NSLayoutConstraint(item: holderView, attribute: .leading, relatedBy: .equal, toItem: topView, attribute: .leading, multiplier: 1.0, constant: 0.0)
let trailingA = NSLayoutConstraint(item: holderView, attribute: .trailing, relatedBy: .lessThanOrEqual, toItem: topView, attribute: .trailing, multiplier: 1.0, constant: 0.0)
let trailingB = NSLayoutConstraint(item: holderView, attribute: .trailing, relatedBy: .equal, toItem: topView, attribute: .trailing, multiplier: 1.0, constant: 0.0)
topB.priority = .defaultLow
bottomB.priority = .defaultLow
leadingB.priority = .defaultLow
trailingB.priority = .defaultLow
NSLayoutConstraint.activate([
topA, topB,
bottomA, bottomB,
leadingA, leadingB,
trailingA, trailingB
])
}
}
Related Topics
How to Get Back "Allow Push Notifications" Dialog After It Was Dismissed Once
Alamofire Download in Background Session
How to Draw a Circle in iOS Swift
Drawviewhierarchyinrect:Afterscreenupdates: Delays Other Animations
How to Split String into Substrings on iOS
Save and Retrieve Value via Keychain
Atos and Dwarfdump Won't Symbolicate My Address
Presenting Viewcontroller with Navigationviewcontroller Swift
Arkit Hide Objects Behind Walls
Uicollectionview Insert Cells Above Maintaining Position (Like Messages.App)
How to Disable Horizontal Scrolling of Uiscrollview
iOS Is It a Static or a Dynamic Framework
How to Use Speech Recognition Inside the iOS Sdk
Front Facing Camera in Uiimagepickercontroller