Suppose in my storyboard, I have a bunch of controller views that align their content to left and right edges with a certain inset (ex: a padding of 6pts). If I later want to change that padding value, how can I quickly make the change across the entire project? Is there a way to change the constant of all constraints with a certain tag in a Storyboard, or do I have to create a kind of "contentView" class and put it in the base view of every ViewController in my project?
You might be able to get the effect you want using a custom subclass of NSLayoutConstraint
:
class AdjustableConstraint: NSLayoutConstraint {
@IBInspectable var name: String = ""
class func setConstant(ofConstraintsNamed name: String, to value: CGFloat) {
constantForName[name] = value
NSNotificationCenter.defaultCenter().postNotificationName(notificationName,
object: self, userInfo: [nameKey: name])
}
override func awakeFromNib() {
super.awakeFromNib()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(AdjustableConstraint.observeAdjustmentNotification(_:)),
name: AdjustableConstraint.notificationName, object: AdjustableConstraint.self)
updateConstant()
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: AdjustableConstraint.notificationName, object: AdjustableConstraint.self)
}
@objc private func observeAdjustmentNotification(note: NSNotification) {
guard
let userInfo = note.userInfo
where userInfo[AdjustableConstraint.nameKey] as? String == name
else { return }
updateConstant()
}
private func updateConstant() {
if let newConstant = AdjustableConstraint.constantForName[name] {
self.constant = newConstant
}
}
private static var constantForName = [String: CGFloat]()
private static let notificationName = "UpdateAdjustableConstraintConstant"
private static let nameKey = "name"
}
Here's how to use it. For all the constraints in the storyboard that you want to adjust together, set their custom class to AdjustableConstraint
. (You can select multiple constraints in the document outline to set the custom class of all of them simultaneously.)
Doing this will make Xcode show a new field, “Name”, in the Attributes Inspector for these constraints. Set the name to some string like “customMargin”:
In your code, you can set the constant of every AdjustableConstraint
with a specific name like this:
AdjustableConstraint.setConstant(ofConstraintsNamed: "customMargin", to: 10)
When an AdjustableConstraint
is loaded from the storyboard, if you have previously set a constant for its name, it will apply that constant. So this will work for newly-loaded constraints too. You might want to initialize the constant before any any constraint is loaded, by setting it in your app delegate at launch time:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
AdjustableConstraint.setConstant(ofConstraintsNamed: "customMargin", to: 30)
return true
}