Last active
September 20, 2016 16:34
-
-
Save johndpope/46a4bb726a38d992d108eba5bb4ac0f2 to your computer and use it in GitHub Desktop.
hybrid xib + snapkit code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// So you have inherited a monolithic complex xib file that extends over 50 constraints. | |
// You change one constraint only to cause something else unrelated to break. | |
// The TotalLossTimeDueToIB.com debt increases. | |
// Xcode upgrades suggests adding more constraints - and slowly the view is becoming harder to juggle. | |
// It's a don't touch it unless it's broken and want to spend hours fixing it kind of smell. | |
// Did I mention Xcode is breaking unsatisfiable constraints errors flooding the console? | |
// | |
// You wish you could make the break - and throw caution to the wind and use a DSL autolayout language like snapkit but it's | |
// too much risky to re-write completely. What if there was way in the middle road? | |
// Instead of ditching the xibs and rolling out ui factory class - what if you could surgically re-wire some of the views to be handled by snapkit and slowly toss out the existing IB constraints. IF so - proceed with caution. | |
// | |
// Don't know snapkit? Checkout | |
// https://github.com/johndpope-karhoo/SnapKitExamples | |
// Instructions | |
// Step 1 - Add tags to your container views in IB | |
// Not using container views? (You probably want to use these where ever possible to hold labels / images etc). | |
// NB. Avoid using IBOutlets if you can to these uiview subclasses. | |
// The code below will remove any xcode constraints imposed by IB on current view. | |
// Step 2. subclass the views in IB to your bespoke OptionsView instead of UIView | |
import Foundation | |
import SnapKit | |
let screenWidth = UIScreen.mainScreen().bounds.width | |
class SnapKitHelperView:UIView{ | |
var debugConstraints = false | |
func getRandomColor() -> UIColor{ | |
let randomGreen:CGFloat = CGFloat(drand48()) | |
let randomBlue:CGFloat = CGFloat(drand48()) | |
return UIColor(red: 1, green: randomGreen, blue: randomBlue, alpha: 1.0) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
if(debugConstraints){ | |
for c in self.constraints{ | |
print("constraints:",c) | |
} | |
self.backgroundColor = self.getRandomColor(); | |
} | |
} | |
func labelByTag(tag:Int) -> UILabel{ | |
if let view = self.viewWithTag(tag) as? UILabel{ | |
return view; | |
}else{ | |
print("FATAL missing label by tag ",tag) | |
fatalError() | |
} | |
return UILabel() | |
} | |
func viewByTag(tag:Int) -> UIView{ | |
if let view = self.viewWithTag(tag){ | |
return view; | |
}else{ | |
print("FATAL missing view by tag ",tag) | |
fatalError() | |
} | |
return UIView() | |
} | |
func imageViewByTag(tag:Int) -> UIImageView{ | |
if let view = self.viewWithTag(tag) as? UIImageView{ | |
return view; | |
}else{ | |
print("FATAL missing image by tag ",tag) | |
fatalError() | |
} | |
return UIImageView() | |
} | |
} | |
class OptionsView:SnapKitHelperView{ | |
private let kPadding: Float = 10.0 | |
private lazy var lineContainer: UIView = self.viewByTag(400) | |
private lazy var cancelContainer: UIView = self.viewByTag(401) | |
private lazy var messageContainer: UIView = self.viewByTag(402) | |
private lazy var callContainer: UIView = self.viewByTag(403) | |
var runOnce = false | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
self.backgroundColor = UIColor.whiteColor(); | |
// REMOVE XCODE CONSTRAINTS ONCE | |
if (!runOnce){ | |
runOnce = true | |
self.removeConstraints(self.constraints) | |
} | |
self.snp_makeConstraints { (make) -> Void in | |
make.width.equalTo(screenWidth) | |
make.height.equalTo(107) | |
} | |
// Top Line | |
lineContainer.snp_makeConstraints { (make) -> Void in | |
make.top.equalTo(self) | |
} | |
// Cancel | |
cancelContainer.snp_makeConstraints { (make) -> Void in | |
make.left.equalTo(self).offset(25) | |
make.top.equalTo(self).offset(10) | |
} | |
//Message | |
callContainer.snp_makeConstraints { (make) -> Void in | |
make.right.equalTo(self).offset(-25) | |
make.top.equalTo(self).offset(10) | |
} | |
// Call Driver | |
messageContainer.snp_makeConstraints { (make) -> Void in | |
make.center.equalTo(self) | |
make.top.equalTo(self).offset(10) | |
} | |
} | |
} | |
N.B - you can recurse into children subviews too if you wish to do so.
for subView in self.subviews{
subView.removeConstraints(subView.constraints)
}
You can use Visual Studio Code -> and change syntax to Jade to get better readability.
Add identifiers to constraints here > http://useyourloaf.com/blog/using-identifiers-to-debug-autolayout/
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example container with IB constraints - these smaller constraint logic for label /heights /widths etc can live another day.
Adding Tags eg. 400 = lineContainer
We want to use snapkit to orchestrate the container layout logic at a higher level.
Here we change the Options uiview to subclass OptionsView instead.
You will want to prefix views with SnapKit - eg. SnapOptionsView to provide clarity to people picking up code next / consider adding to readme if need be.