Layout UIViews with method chaining, avoid messy frame calculations

I’ve been making a lot of UI Interfaces recently, and though its not difficult calculating all the frames, centering view within a view, offsetting from the top left or bottom right. It’s something we’re all used to, It’s just math. But after a while, it really gets tedious and annoying. What if we could layout our subviews without doing that much calculations?

But wait you say, isn't that what AutoLayout is for!!??

I like AutoLayout but AutoLayout is a all or nothing approach, you either use auto layout for all the views on this layout or you use none. Sometimes when you want to debug the user interface but can't get the frame or size of the element. Or you want to keep the UI dynamic but don't want to have so many constraints set as variables (it can get ugly sometimes).

You ever have that moment, where you use AutoLayout in the beginning and everything was awesome, but after the view got really complicated, you scratch your head and say, wow I should've just used frame calculations, things would be much easier to resolve... but you can't! cuz once you use AutoLayout, you gotta use it all the way.

I wanted something that felt like AutoLayout, that does the math for me, puts things in place, but can also use frame operations on it to interchangeably. Basically something that looks like your doing auto layout, but its just calculating the frames for you under the hood so you don't have to do it.

That’s when I started working on a UIView Extensions in Swift that does that for you, it is also chainable making layingout UIs feel functional and a lot more condensed. Often only needing one line to layout a subview. This made life easier for me, maybe it will for you too, Let me know what you think!

I've only made some basic functionalities for laying out the UI, I plan to incorporate more in the future if I find this useful enough.

So here it is:

JWChainableUIView

JWChainableUIView allows you to chain functions of initialization, addSubview, customization your UIView.

Making it simpler to create and layout subviews, avoiding messy frame calculations.

Examples :

Making a Japanese Flag

japaneseFlagView.initSubviewInCenter(classType: CircleView.self, size: CGSize(width: 50, height: 50))
.changeBackgroundColor(UIColor.redColor())
.changeAlpha(0.5)

Making Mickey Mouse

mickyMouseView.initSubviewInBottomCenter(classType: CircleView.self, size: CGSize(width: 80, height: 80))
.changeBackgroundColor(UIColor.blackColor())
.offSet(x: 0, y: -10)
mickyMouseView.initSubviewInTopLeft(classType: CircleView.self, size: CGSize(width: 35, height: 35))
.changeBackgroundColor(UIColor.blackColor())
.offSet(x: 10, y: 15)
mickyMouseView.initSubviewInTopRight(classType: CircleView.self, size: CGSize(width: 35, height: 35))
.changeBackgroundColor(UIColor.blackColor())
.offSet(x: -10, y: 15)

Making an American Flag

let stripeHeight: CGFloat = 1000.0 / 13
for index in 0..<13 {
    let redStripe = americanFlagView.initSubview(classType: UIView.self, size: CGSize(width: 1500, height: stripeHeight))
.offSet(x: 0, y: CGFloat(index) * stripeHeight)
    if index % 2 == 0 {
redStripe.changeBackgroundColor(UIColor.redColor())
}
}
let bluePart = americanFlagView.initSubviewInTopLeft(classType: UIView.self, size: CGSize(width: 500, height: 500))
.changeBackgroundColor(UIColor.blueColor())
for index in 0..<49 {
    let y = CGFloat(index / 7) * 500.0 / 7
let x = CGFloat(index % 7) * 500.0 / 7
    bluePart.initSubview(classType: StarView.self, size: CGSize(width: 50, height: 50))
.offSet(x: x, y: y)
}

Usage :

Chaining:

view.initSubview(classType: UIView.self, size: CGSize(width: 50, height: 50))
.changeAlpha(0.5)
.changeBackgroundColor(UIColor.blackColor())
.align(alignment: .Right, .Bottom)
.offSet(x: 15, y: 15)

Alignment:

public enum HorizontalAlignment {
case Left, Center, Right
}
public enum VerticalAlignment {
case Top, Center, Bottom
}
//Align view in the top left corner of superview 
view.align(alignment: .Left, .Top)

Moving:

view.moveToCenter()
view.moveToTopLeft()
view.moveToTopRight()
view.moveToTopCenter()
view.moveToBottomLeft()
view.moveToBottomRight()
view.moveToBottomCenter()
view.moveToLeftCenter()
view.moveToRightCenter()

Convenience initializers make it even simpler to initialize your subview exactly where you want in one line.

view.initSubviewInCenter(classType: CircleView.self, size: size)
view.initSubviewInTopLeft(classType: CircleView.self, size: size)
view.initSubviewInTopRight(classType: CircleView.self, size: size)
view.initSubviewInTopCenter(classType: CircleView.self, size: size)
view.initSubviewInBottomLeft(classType: CircleView.self, size: size)
view.initSubviewInBottomRight(classType: CircleView.self, size: size)
view.initSubviewInBottomCenter(classType: CircleView.self, size: size)
view.initSubviewInLeftCenter(classType: CircleView.self, size: size)
view.initSubviewInRightCenter(classType: CircleView.self, size: size)

Installation

  1. Download the project. https://github.com/jackywang135/JWChainableUIView
  2. Open the “JWChainableUIView.playground” if you want to play around and experiment with the methods. All examples above are included in the playground.
  3. Copy the “JWChainableUIViewExtension.swift” from the “Sources” folder and add it to the project you want to use it in.

Let me know if you find this useful for you or have any suggestions and feedback!

GitHub | Twitter | Facebook | JackyWangDeveloper@gmail.com

Thanks for reading, Happy Coding!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.