Skip to content

Instantly share code, notes, and snippets.

@johndpope
Last active September 20, 2016 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johndpope/46a4bb726a38d992d108eba5bb4ac0f2 to your computer and use it in GitHub Desktop.
Save johndpope/46a4bb726a38d992d108eba5bb4ac0f2 to your computer and use it in GitHub Desktop.
hybrid xib + snapkit code
// 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)
}
}
}
@johndpope
Copy link
Author

johndpope commented Sep 16, 2016

Example container with IB constraints - these smaller constraint logic for label /heights /widths etc can live another day.
screen shot 2016-09-16 at 11 22 44

Adding Tags eg. 400 = lineContainer
screen shot 2016-09-16 at 11 32 37

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.
test

@johndpope
Copy link
Author

N.B - you can recurse into children subviews too if you wish to do so.
for subView in self.subviews{
subView.removeConstraints(subView.constraints)
}

@johndpope-karhoo
Copy link

johndpope-karhoo commented Sep 16, 2016

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/

screen shot 2016-09-16 at 14 50 06

@johndpope-karhoo
Copy link

Probably obsolete with xcode 8 - but you can dig up these labels / constraints here
fix-constraints

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment