Programmatic view layout for the rest of us.

Related tags

Layout Facade
Overview

Façade

License Build Status Badge w/ Version Coverage Status Carthage compatible

Important

Facade is no longer under active development, and as such if you create any issues or submit pull requests, it's not very likely to be integrated. Thanks to all that helped make Facade better over the last few years!

What is it?

Façade is a UIView category allowing you to build your UI in real-world terms, in the same way you would explain the layout to someone in conversation. It is a conglomeration of convenience methods wrapping lots of annoying and tedius frame algebra into a human-readable format. Because of this, it's lightweight and flexible enough to allow you to build great looking UI's quickly and easily define unique layout experiences based on device orientation or type.

Demo

[_headerImageView anchorTopCenterFillingWidthWithLeftAndRightPadding:0 topPadding:0 height:250];

NSArray *shareButtons = @[_facebookButton, _twitterButton, _googleButton, _pinterestButton];
[_headerImageView groupVertically:shareButtons centerRightWithRightPadding:7 spacing:7 width:45 height:45];

[_avatarImageView alignUnder:_headerImageView matchingCenterWithTopPadding:-50 width:100 height:100];
[_nameLabel alignUnder:_avatarImageView centeredFillingWidthWithLeftAndRightPadding:7 topPadding:14 height:28];
[_usernameLabel alignUnder:_nameLabel centeredFillingWidthWithLeftAndRightPadding:7 topPadding:2 height:19];

[_bioLabel sizeToFit];
[_bioLabel alignUnder:_usernameLabel centeredFillingWidthWithLeftAndRightPadding:15 topPadding:10 height:CGRectGetHeight(_bioLabel.frame)];

[_followButton alignUnder:_bioLabel matchingCenterWithTopPadding:20 width:250 height:44];

[_scrollView groupHorizontally:@[_messageButton, _statsButton, _addButton] centeredUnderView:_followButton topPadding:30 spacing:40 width:60 height:60];
[_messageLabel alignUnder:_messageButton matchingCenterWithTopPadding:7 width:80 height:13];
[_statsLabel alignUnder:_statsButton matchingCenterWithTopPadding:7 width:80 height:13];
[_addLabel alignUnder:_addButton matchingCenterWithTopPadding:7 width:80 height:13];

How Do I Use It?

  1. Add pod 'Facade' to your Podfile, and run pod install
  2. Import UIView+Facade.h in your view controller.
  3. Create your view components like you normally would, customize them, and add them as subviews to their appropriate superview. Don't set their frames - let us handle that for you.
  4. When appropriate, such as in your UIViewController's viewWillLayoutSubviews or UIView's layoutSubviews method, call the applicable UIView+Facade convenience methods to define how you want your UI to be laid out.

Creating Anchor Views

Many UI layouts "start" with a view anchored to the top/corner of the screen, such as a profile view with an avatar in the top-left corner. Doing something like this is easy with Façade - simply tell the view where to anchor itself, and provide the applicable padding/size parameters, and it will do the rest for you. Doing this in viewWillLayoutSubviews also allows Façade to keep this layout consistent in both orientations, as shown below:

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    [self layoutFacade];
}

- (void)layoutFacade {
    CGFloat padding = 10;
    CGFloat size = 50;

    [_redView anchorTopLeftWithLeftPadding:padding topPadding:padding width:size height:size];
    [_orangeView anchorTopCenterWithTopPadding:padding width:size height:size];
    [_yellowView anchorTopRightWithRightPadding:padding topPadding:padding width:size height:size];
    [_greenView anchorCenterRightWithRightPadding:padding width:size height:size];
    [_blueView anchorBottomRightWithRightPadding:padding bottomPadding:padding width:size height:size];
    [_purpleView anchorBottomCenterWithBottomPadding:padding width:size height:size];
    [_cyanView anchorBottomLeftWithLeftPadding:padding bottomPadding:padding width:size height:size];
    [_brownView anchorCenterLeftWithLeftPadding:padding width:size height:size];
    [_grayView anchorInCenterWithWidth:size height:size];
}

Example 1A Example 1B

Relatives

While most layouts start with one or more anchor views, the rest of the components are typically laid out relative to other sibling views and often their sizes are dependant both on these sibling views and their superview. We've compiled the most common relative layout types to make this process as easy as possible. Here are a few examples, showing the results in both orientations:

[_redView anchorTopLeftWithLeftPadding:10 topPadding:10 width:100 height:100];
[_orangeView alignToTheRightOf:_redView matchingTopAndFillingWidthWithLeftAndRightPadding:10 height:20];
[_greenView alignUnder:_orangeView matchingLeftAndFillingWidthWithRightPadding:10 topPadding:5 height:20];
[_blueView alignUnder:_greenView matchingLeftAndFillingWidthWithRightPadding:10 topPadding:5 height:50];
[_brownView alignUnder:_redView matchingLeftAndFillingWidthWithRightPadding:10 topPadding:10 height:30];
[_purpleView alignUnder:_brownView matchingRightWithTopPadding:10 width:100 height:40];
[_yellowView alignUnder:_purpleView centeredFillingWidthAndHeightWithLeftAndRightPadding:10 topAndBottomPadding:10];

Example 2A Example 2B

You can also position views between two views vertically or horizontally:

[_purpleView alignBetweenLeft:_orangeView andRight:_yellowView matchingTopWithLeftAndRightPadding:10 height:50];
[_brownView alignBetweenTop:_orangeView andBottom:_greenView matchingLeftWithTopAndBottomPadding:10 width:50];
[_grayView alignBetweenLeft:_greenView andRight:_blueView matchingTopWithLeftAndRightPadding:10 height:50];
[_cyanView alignBetweenTop:_yellowView andBottom:_blueView matchingLeftWithTopAndBottomPadding:10 width:50];

Example 4A Example 4B

View Groups

Sometimes you want a number of view components to be grouped together and have this group as a whole be laid out relative to another view. A common example of this would be share buttons - perhaps on top of an image there's share icons for facebook, pinterest, twitter, etc. This can easily be achieved by telling the appropriate superview to group an array of child views with a particular layout, padding, and sizes. Here's two-examples-in-one:

[_redView groupVertically:@[_orangeView, _yellowView, _greenView] inUpperRightWithRightPadding:10 topPadding:10 spacing:10 width:50 height:50];
[self.view groupHorizontally:@[_blueView, _purpleView, _brownView] centeredUnderView:_redView topPadding:10 spacing:10 width:50 height:50];

Example 3A

The cool part of this is that it allows you to add, remove, or reorganize views to a group without having to recalculate all of the frames for each.

[_redView groupVertically:@[_orangeView, _yellowView] inUpperRightWithRightPadding:10 top:10 spacing:10 width:50 height:50];
[self.view groupHorizontally:@[_greenView, _blueView, _purpleView, _brownView, _blackView] centeredUnderView:_redView topPadding:10 spacing:10 width:50 height:50];

Example 3B

Considerations

  • I simply don't have the time to consider every single layout scenario, and thus it might not be a perfect fit for every situation. I invested quite some time looking at screenshot after screenshot from countless mobile apps to see how each view lays out its components, and in trying to keep the API as simple as possible, certain assumptions are made that in my opinion will be sufficient for the vast majority of mobile UIs, but your mileage may vary. I've almost certainly missed implementing methods that might also be commonly used - and if I did please open an issue or a pull request!
  • I know the APIs are quite verbose - this is by design. I intentionally chose readability, clarity, and specificity over succinctness because in this case I feel choosing the methods you'll need to achieve your desired goals will be easier as you won't need to rely on the documentation, and maintenance will be much more pleasnt as anyone looking at the code will very-quickly know exactly that it means.

Community

  • If you want to contribute, open a pull request. Please do your best to keep the style/formatting consistent with the current project and MAKE SURE TO ADD TESTS!

  • If you have questions, feature requests, etc., I would prefer if you created an issue rather than email me directly.

License

This project is made available under the MIT license. See LICENSE.txt for details.

Comments
  • Add groupGrid fillingWidthAndHeightWithColumnCount method

    Add groupGrid fillingWidthAndHeightWithColumnCount method

    groupGrid fillingWidthWithColumnCount produces inconsistent height when the screen is rotated for fixed height elements. The width size is being calculated to distribute the items evenly and the same calculated value is being used for height parameter in CGRectMake. This is not true for elements who has fixed height but needs to be distributed evenly through their parents width. Please check the attached screen shots.

    In Portrait Mode : All is good screen shot 2015-07-01 at 8 58 36 am

    Using groupGrid fillingWidthWithColumnCount method in Landscape Mode: Inconsistent height screen shot 2015-07-01 at 8 59 42 am

    groupGrid fillingWidthAndHeightWithColumnCount method in Landscape Mode: All is good screen shot 2015-07-01 at 8 59 00 am

    opened by roshangautam 14
  • Rounded UIImageView not showing

    Rounded UIImageView not showing

    Hello,

    I'm using

        self.imagerView = [UIImageView new];
        self.imagerView.layer.cornerRadius = self.imagerView.frame.size.width / 2;
        self.imagerView.clipsToBounds = YES;
        [self.containerView addSubview:self.imagerView];
    

    and

    [self.imagerView anchorTopLeftWithLeftPadding:10 topPadding:10 width:50 height:50];
    

    But UIimageView is not rounding as expected.

    Please advise.

    question 
    opened by danglade 6
  • Animations of a group or a view

    Animations of a group or a view

    Is it possible to apply animations to a group as a whole, and/or apply an animation block to a group such that each view inside will use it?

    Or all views should just be treated regularly?

    question 
    opened by guyisra 5
  • Here's a Swift Implementation!

    Here's a Swift Implementation!

    Here's a SWIFT implementation! It may need some optimization love, but should be 100% compliant to modern SWIFT libs. (Anything Doubles Related needs looking into for perf sake at least.)

    Swift Version Below:

    //
    //  UIView.swift+(Facade)
    //  Copyright Go Nuts and Have Fun!
    //
    
    import Foundation
    import UIKit
    
    extension UIView {
    
        func fCenter() -> CGPoint {
    
            var center = CGPoint(x: self.frame.midX - self.frame.minX,y: self.frame.midY - self.frame.minY);
    
            return center;
        }
    
        func xMin() -> CGFloat {
            return CGRectGetMinX(self.frame)
        }
    
        func xMax() -> CGFloat {
            return CGRectGetMaxX(self.frame)
        }
    
        func yMin() -> CGFloat {
            return CGRectGetMinY(self.frame)
        }
    
        func yMax() -> CGFloat {
            return CGRectGetMaxY(self.frame)
        }
    
        func width() -> CGFloat {
            return CGRectGetWidth(self.frame)
        }
    
        func height() -> CGFloat {
            return CGRectGetHeight(self.frame)
        }
    
        func fillSuperview() {
            self.frame = CGRectMake(0, 0, CGRectGetWidth(self.superview!.frame), CGRectGetHeight(self.superview!.frame))
        }
    
        func anchorTopLeftWithLeftPadding(left: CGFloat, topPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, top, width, height)
        }
    
        func anchorTopRightWithRightPadding(right: CGFloat, topPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetWidth(self.superview!.frame) - width - right, top, width, height)
        }
    
        func anchorBottomLeftWithLeftPadding(left: CGFloat, bottomPadding bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, CGRectGetHeight(self.superview!.frame) - height - bottom, width, height)
        }
    
        func anchorBottomRightWithRightPadding(right: CGFloat, bottomPadding bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetWidth(self.superview!.frame) - width - right, CGRectGetHeight(self.superview!.frame) - height - bottom, width, height)
        }
    
        func anchorInCenterWithWidth(width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake((CGRectGetWidth(self.superview!.frame) / 2.0) - (width / 2.0), (CGRectGetHeight(self.superview!.frame) / 2.0) - (height / 2.0), width, height)
        }
    
        func anchorCenterLeftWithLeftPadding(left: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, (CGRectGetHeight(self.superview!.frame) / 2.0) - (height / 2.0), width, height)
        }
    
        func anchorCenterRightWithRightPadding(right: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetWidth(self.superview!.frame) - width - right, (CGRectGetHeight(self.superview!.frame) / 2.0) - (height / 2.0), width, height)
        }
    
        func anchorTopCenterWithTopPadding(top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake((CGRectGetWidth(self.superview!.frame) / 2.0) - (width / 2.0), top, width, height)
        }
    
        func anchorBottomCenterWithBottomPadding(bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake((CGRectGetWidth(self.superview!.frame) / 2.0) - (width / 2.0), CGRectGetHeight(self.superview!.frame) - height - bottom, width, height)
        }
    
        func anchorInCenterFillingWidthAndHeightWithLeftAndRightPadding(leftAndRight: CGFloat, topAndBottomPadding topAndBottom: CGFloat) {
            self.frame = CGRectMake(leftAndRight, topAndBottom, CGRectGetWidth(self.superview!.frame) - (2 * leftAndRight), CGRectGetHeight(self.superview!.frame) - (2 * topAndBottom))
        }
    
        func anchorTopCenterFillingWidthWithLeftAndRightPadding(leftAndRight: CGFloat, topPadding top: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, top, CGRectGetWidth(self.superview!.frame) - (2 * leftAndRight), height)
        }
    
        func anchorBottomCenterFillingWidthWithLeftAndRightPadding(leftAndRight: CGFloat, bottomPadding bottom: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetHeight(self.superview!.frame) - height - bottom, CGRectGetWidth(self.superview!.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheRightOf(view: UIView, withLeftPadding left: CGFloat, topPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + left, top, width, height)
        }
    
        func alignToTheRightOf(view: UIView, fillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, topPadding top: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + leftAndRight, top, CGRectGetWidth(self.superview!.frame) - CGRectGetMaxX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheRightOf(view: UIView, matchingTopWithLeftPadding left: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + left, CGRectGetMinY(view.frame), width, height)
        }
    
        func alignToTheRightOf(view: UIView, matchingTopAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + leftAndRight, CGRectGetMinY(view.frame), CGRectGetWidth(view.superview!.frame) - CGRectGetMaxX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheRightOf(view: UIView, matchingCenterWithLeftPadding left: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + left, CGRectGetMidY(view.frame) - (height / 2.0), width, height)
        }
    
        func alignToTheRightOf(view: UIView, matchingCenterAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + leftAndRight, CGRectGetMidY(view.frame) - (height / 2.0), CGRectGetWidth(view.superview!.frame) - CGRectGetMaxX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheRightOf(view: UIView, matchingBottomWithLeftPadding left: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + left, CGRectGetMaxY(view.frame) - height, width, height)
        }
    
        func alignToTheRightOf(view: UIView, matchingBottomAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) + leftAndRight, CGRectGetMaxY(view.frame) - height, CGRectGetWidth(view.superview!.frame) - CGRectGetMaxX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheLeftOf(view: UIView, fillingWidthAndHeightWithLeftAndRightPadding leftAndRight: CGFloat, topAndBottomPadding topAndBottom: CGFloat) {
            self.frame = CGRectMake(leftAndRight, topAndBottom, CGRectGetMinX(view.frame) - (2 * leftAndRight), CGRectGetHeight(self.superview!.frame) - (2 * topAndBottom))
        }
    
        func alignToTheLeftOf(view: UIView, matchingTopWithRightPadding right: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame) - width - right, CGRectGetMinY(view.frame), width, height)
        }
    
        func alignToTheLeftOf(view: UIView, matchingTopAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMinY(view.frame), CGRectGetMinX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheLeftOf(view: UIView, matchingCenterWithRightPadding right: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame) - width - right, CGRectGetMidY(view.frame) - (height / 2.0), width, height)
        }
    
        func alignToTheLeftOf(view: UIView, matchingCenterAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMidY(view.frame) - (height / 2.0), CGRectGetMinX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignToTheLeftOf(view: UIView, matchingBottomWithRightPadding right: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame) - width - right, CGRectGetMaxY(view.frame) - height, width, height)
        }
    
        func alignToTheLeftOf(view: UIView, matchingBottomAndFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMaxY(view.frame) - height, CGRectGetMinX(view.frame) - (2 * leftAndRight), height)
        }
    
        func alignUnder(view: UIView, withLeftPadding left: CGFloat, topPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, CGRectGetMaxY(view.frame) + top, width, height)
        }
    
        func alignUnder(view: UIView, withRightPadding right: CGFloat, topPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(self.superview!.frame) - width - right, CGRectGetMaxY(view.frame) + top, width, height)
        }
    
        func alignUnder(view: UIView, matchingLeftWithTopPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMaxY(view.frame) + top, width, height)
        }
    
        func alignUnder(view: UIView, matchingLeftAndFillingWidthWithRightPadding right: CGFloat, topPadding top: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMaxY(view.frame) + top, CGRectGetWidth(view.superview!.frame) - CGRectGetMinX(view.frame) - right, height)
        }
    
        func alignUnder(view: UIView, matchingCenterWithTopPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMidX(view.frame) - (width / 2.0), CGRectGetMaxY(view.frame) + top, width, height)
        }
    
        func alignUnder(view: UIView, centeredFillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, topPadding top: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMaxY(view.frame) + top, CGRectGetWidth(view.superview!.frame) - (2 * leftAndRight), height)
        }
    
        func alignUnder(view: UIView, centeredFillingWidthAndHeightWithLeftAndRightPadding leftAndRight: CGFloat, topAndBottomPadding topAndBottom: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMaxY(view.frame) + topAndBottom, CGRectGetWidth(view.superview!.frame) - (2 * leftAndRight), CGRectGetHeight(self.superview!.frame) - CGRectGetMaxY(view.frame) - topAndBottom - topAndBottom)
        }
    
        func alignUnder(view: UIView, matchingRightWithTopPadding top: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) - width, CGRectGetMaxY(view.frame) + top, width, height)
        }
    
        func alignUnder(view: UIView, matchingRightAndFillingWidthWithLeftPadding left: CGFloat, topPadding top: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, CGRectGetMaxY(view.frame) + top, CGRectGetMinX(view.frame) + CGRectGetWidth(view.frame) - left, height)
        }
    
        func alignUnder(view: UIView, matchingLeftAndRightFillingHeightWithTopPadding top: CGFloat, bottomPadding bottom: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMaxY(view.frame) + top, CGRectGetWidth(view.frame), CGRectGetHeight(self.superview!.frame) - CGRectGetMaxY(view.frame) - top - bottom)
        }
    
        func alignUnder(view: UIView, matchingLeftFillingWidthAndHeightWithRightPadding right: CGFloat, topPadding top: CGFloat, bottomPadding bottom: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMaxY(view.frame) + top, CGRectGetWidth(self.superview!.frame) - CGRectGetMinX(view.frame) - right, CGRectGetHeight(self.superview!.frame) - CGRectGetMaxY(view.frame) - top - bottom)
        }
    
        func alignAbove(view: UIView, matchingLeftWithBottomPadding bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMinY(view.frame) - height - bottom, width, height)
        }
    
        func alignAbove(view: UIView, matchingLeftAndFillingWidthWithRightPadding right: CGFloat, bottomPadding bottom: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMinX(view.frame), CGRectGetMinY(view.frame) - height - bottom, CGRectGetWidth(view.superview!.frame) - CGRectGetMinX(view.frame) - right, height)
        }
    
        func alignAbove(view: UIView, matchingCenterWithBottomPadding bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMidX(view.frame) - (width / 2.0), CGRectGetMinY(view.frame) - height - bottom, width, height)
        }
    
        func alignAbove(view: UIView, fillingWidthWithLeftAndRightPadding leftAndRight: CGFloat, bottomPadding bottom: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMinY(view.frame) - height - bottom, CGRectGetWidth(view.superview!.frame) - (2 * leftAndRight), height)
        }
    
        func alignAbove(view: UIView, matchingRightWithBottomPadding bottom: CGFloat, width: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(CGRectGetMaxX(view.frame) - width, CGRectGetMinY(view.frame) - height - bottom, width, height)
        }
    
        func alignAbove(view: UIView, matchingRightAndFillingWidthWithLeftPadding left: CGFloat, bottomPadding bottom: CGFloat, height: CGFloat) {
            self.frame = CGRectMake(left, CGRectGetMinY(view.frame) - height - bottom, CGRectGetMinX(view.frame) + CGRectGetWidth(view.frame) - left, height)
        }
    
        func alignBetweenLeft(leftView: UIView, andRight rightView: UIView, matchingTopWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            var xOrigin: CGFloat = CGRectGetMaxX(leftView.frame) + leftAndRight
            self.frame = CGRectMake(xOrigin, CGRectGetMinY(leftView.frame), CGRectGetWidth(self.superview!.frame) - xOrigin - (CGRectGetWidth(self.superview!.frame) - CGRectGetMinX(rightView.frame)) - leftAndRight, height)
        }
    
        func alignBetweenLeft(leftView: UIView, andRight rightView: UIView, matchingCenterWithLeftAndRightPadding leftAndRight: CGFloat, height: CGFloat) {
            var xOrigin: CGFloat = CGRectGetMaxX(leftView.frame) + leftAndRight
            self.frame = CGRectMake(xOrigin, CGRectGetMidY(leftView.frame) - (height / 2.0), CGRectGetWidth(self.superview!.frame) - xOrigin - (CGRectGetWidth(self.superview!.frame) - CGRectGetMinX(rightView.frame)) - leftAndRight, height)
        }
    
        func alignBetweenTop(topView: UIView, andBottom bottomView: UIView, matchingLeftWithTopAndBottomPadding topAndBottom: CGFloat, width: CGFloat) {
            var yOrigin: CGFloat = CGRectGetMaxY(topView.frame) + topAndBottom
            self.frame = CGRectMake(CGRectGetMinX(topView.frame), CGRectGetMaxY(topView.frame) + topAndBottom, width, CGRectGetHeight(self.superview!.frame) - yOrigin - (CGRectGetHeight(self.superview!.frame) - CGRectGetMinY(bottomView.frame)) - topAndBottom)
        }
    
        func alignBetweenTop(topView: UIView, andBottom bottomView: UIView, centeredWithLeftAndRightPadding leftAndRight: CGFloat, topAndBottomPadding topAndBottom: CGFloat) {
            self.frame = CGRectMake(leftAndRight, CGRectGetMaxY(topView.frame) + topAndBottom, CGRectGetWidth(self.superview!.frame) - (2 * leftAndRight), CGRectGetMinY(bottomView.frame) - CGRectGetMaxY(topView.frame) - (2 * topAndBottom))
        }
    
        //Mark: Anything Referencing Doubles Below is My Stupid Fixes. Not required, and likely needing optimization.
    
        func groupHorizontally(views: [UIView], centeredUnderView view: UIView, topPadding top: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
    
            var space:Double = Double(spacing);
            var count:Double = Double(views.count);
            var frameWidth:Double = Double(CGRectGetWidth(self.frame));
            var maxWidth = Double(count) * Double(width);
            var xO: Double = (frameWidth - (maxWidth) - ((count - 1) * space)) / 2.0
    
            var xOrigin:CGFloat = CGFloat(xO);
    
            for subview: UIView in views {
                subview.frame = CGRectMake(xOrigin, CGRectGetMaxY(view.frame) + top, width, height)
                xOrigin += width + spacing
            }
        }
    
        func groupHorizontally(subviews: [UIView], fillingWidthAndHeightWithTopAndBottomPadding topAndBottom: CGFloat, spacing: CGFloat) {
    
            var top:Double = Double(topAndBottom);
            var space:Double = Double(spacing);
            var subviewCount:Double = Double(subviews.count)
            var frameWidth:Double = Double(CGRectGetWidth(self.frame));
            var frameHeight:Double = Double(CGRectGetHeight(self.frame));
            var w: Double = (frameWidth - ((subviewCount + 1) * space)) / subviewCount
            var h: Double = frameHeight - (2 * top)
    
            var xOrigin: CGFloat = spacing
            var width:CGFloat = CGFloat(w);
            var height:CGFloat = CGFloat(h);
    
            for subview: UIView in subviews {
                subview.frame = CGRectMake(xOrigin, topAndBottom, width, height)
                xOrigin += width + spacing
            }
        }
    
        func groupHorizontally(views: [UIView], fillingHeightWithLeftPadding left: CGFloat, spacing: CGFloat, topAndBottomPadding topAndBottom: CGFloat, width: CGFloat) {
            var xOrigin: CGFloat = left
            var height: CGFloat = CGRectGetHeight(self.frame) - (2 * topAndBottom)
            for subview: UIView in views {
                subview.frame = CGRectMake(xOrigin, topAndBottom, width, height)
                xOrigin += width + spacing
            }
        }
    
    
        func groupVertically(subviews: [UIView], inUpperRightWithRightPadding right: CGFloat, topPadding top: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
            var yOrigin: CGFloat = top
            for view: UIView in subviews {
                view.frame = CGRectMake(CGRectGetWidth(self.frame) - width - right, yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], centerRightWithRightPadding right: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
    
            var frameHeight:Double = Double(CGRectGetHeight(self.frame));
            var count = Double(subviews.count);
            var h:Double = Double(height);
            var maxHeight:Double = Double(count * h);
            var space:Double = Double(spacing);
            var yO:Double = (frameHeight - (maxHeight) - ((count - 1) * space)) / 2.0
    
            var yOrigin: CGFloat = CGFloat(yO);
    
            for view: UIView in subviews {
                view.frame = CGRectMake(CGRectGetWidth(self.frame) - width - right, yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], inLowerRightWithRightPadding right: CGFloat, bottomPadding bottom: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
    
    
            var h:Double = Double(height);
            var b:Double = Double(bottom);
            var frameHeight:Double = Double(CGRectGetHeight(self.frame));
            var yO:Double = Double(frameHeight - h - b);
    
            var yOrigin: CGFloat = CGFloat(yO);
            for view: UIView in subviews {
                view.frame = CGRectMake(CGRectGetWidth(self.frame) - width - right, yOrigin, width, height)
                yOrigin -= height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], inUpperLeftWithLeftPadding left: CGFloat, topPadding top: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
            var yOrigin: CGFloat = top
            for view: UIView in subviews {
                view.frame = CGRectMake(left, yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], centerLeftWithLeftPadding left: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
    
            var frameHeight:Double = Double(CGRectGetHeight(self.frame));
            var count:Double = Double(subviews.count);
            var h:Double = Double(height);
            var maxHeight:Double = Double(count * h);
            var space:Double = Double(spacing);
            var yO:Double = (frameHeight - (maxHeight) - ((count - 1) * space)) / 2.0
    
            var yOrigin: CGFloat = CGFloat(yO);
            for view: UIView in subviews {
                view.frame = CGRectMake(left, yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], inLowerLeftWithLeftPadding left: CGFloat, bottomPadding bottom: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
            var yOrigin: CGFloat = CGRectGetHeight(self.frame) - height - bottom
            for view: UIView in subviews {
                view.frame = CGRectMake(left, yOrigin, width, height)
                yOrigin -= height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], topCenterWithTopPadding top: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
            var yOrigin: CGFloat = top
            for view: UIView in subviews {
                view.frame = CGRectMake((CGRectGetWidth(self.frame) / 2.0) - (width / 2.0), yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], centerWithSpacing spacing: CGFloat, width: CGFloat, height: CGFloat) {
    
            var frameHeight:Double = Double(CGRectGetHeight(self.frame));
            var count:Double = Double(subviews.count);
            var h: Double = Double(height);
            var maxHeight:Double = Double(count * h);
            var space:Double = Double(spacing);
            var yO:Double = Double((frameHeight - (maxHeight) - ((count - 1) * space)) / 2.0)
    
            var yOrigin: CGFloat = CGFloat(yO);
            for view: UIView in subviews {
                view.frame = CGRectMake((CGRectGetWidth(self.frame) / 2.0) - (width / 2.0), yOrigin, width, height)
                yOrigin += height + spacing
            }
        }
    
        func groupVertically(subviews: [UIView], bottomCenterWithBottomPadding bottom: CGFloat, spacing: CGFloat, width: CGFloat, height: CGFloat) {
            var yOrigin: CGFloat = CGRectGetHeight(self.frame) - height - bottom
            for view: UIView in subviews {
                view.frame = CGRectMake((CGRectGetWidth(self.frame) / 2.0) - (width / 2.0), yOrigin, width, height)
                yOrigin -= height + spacing
            }
        }
    
        func groupGrid(subviews: [UIView], fillingWidthWithColumnCount columnCount: UInt, spacing: CGFloat) {
            var currentColumn: UInt = 0
            var xOrigin: CGFloat = spacing
            var yOrigin: CGFloat = spacing
    
            var frameWidth:Double = Double(CGRectGetWidth(self.frame));
            var count:Double = Double(columnCount);
            var space:Double = Double(spacing);
    
            var s:Double = Double((frameWidth - ((count + 1) * space) / count));
            var size: CGFloat = CGFloat(s);
    
            var offset: CGFloat = size + spacing
            for subview: UIView in subviews {
                subview.frame = CGRectMake(xOrigin, yOrigin, size, size)
                if currentColumn == columnCount - 1 {
                    currentColumn = 0
                    xOrigin = spacing
                    yOrigin += offset
                }
                else {
                    currentColumn++
                    xOrigin += offset
                }
            }
        }
    }
    
    enhancement 
    opened by mpelham 2
  • Carthage compatibility

    Carthage compatibility

    https://github.com/Carthage/Carthage

    Currently it says "Dependency "Facade" has no shared framework schemes", so we need create framework and share its schema.

    opened by MontakOleg 1
  • What to do in times of UIStackView?

    What to do in times of UIStackView?

    Hey @mamaral

    how are you? I just stumbled upon your Project and it looks really cool. But Apple announced UIStackView and i am asking myself what the advantage is, using Facaded in comparisson to Apples Solution.

    question 
    opened by buk 1
Releases(v1.1.1)
Owner
Mike
Mike
Concise Auto Layout API to chain programmatic constraints while easily updating existing constraints.

Concise API for Auto Layout. SnapLayout extends UIView and NSView to deliver a list of APIs to improve readability while also shortening constraint co

Satinder Singh 11 Dec 17, 2021
Swifty DSL for programmatic Auto Layout in iOS

WWLayout Easy to write auto layout constraints, with minimal extensions to standard namespaces. Feature Highlights Easy to use, readable API Backwards

WW Tech 49 Oct 2, 2022
Auto Layout (and manual layout) in one line.

Auto Layout (and manual layout) in one line. Quick Look view.bb.centerX().below(view2).size(100) It’s equivalent to iOS 9 API: view.centerXAnchor.cons

Javier Zhang 74 Oct 19, 2022
Auto Layout made easy with the Custom Layout.

Auto Layout made easy with the Custom Layout. Getting started CocoaPods CocoaPods is a dependency manager for Cocoa projects. You can install it with

Malith Nadeeshan 1 Jan 16, 2022
AppStoreClone - Understanding the complex layout of app store using UICompositional layout in swift

AppStoreClone Understanding the complex layout of app store using UICompositiona

Dheeraj Kumar Sharma 8 Dec 28, 2022
A custom layout built on top of SwiftUI's Layout API that lays elements out in multiple lines. Similar to flex-wrap in CSS, CollectionViewFlowLayout.

WrapLayout A custom layout built on top of SwiftUI's Layout API that lays elements out in multiple lines. Similar to flex-wrap in CSS, CollectionViewF

Hiroshi Kimura 6 Sep 27, 2022
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.

?? UNMAINTAINED ?? This project is no longer used by LinkedIn and is currently unmaintained. LayoutKit is a fast view layout library for iOS, macOS, a

LinkedIn's Attic 3.2k Dec 27, 2022
Flow layout / tag cloud / collection view in SwiftUI.

SwiftUIFlowLayout A Flow Layout is a container that orders its views sequentially, breaking into a new "line" according to the available width of the

Gordan Glavaš 115 Dec 28, 2022
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.

?? UNMAINTAINED ?? This project is no longer used by LinkedIn and is currently unmaintained. LayoutKit is a fast view layout library for iOS, macOS, a

LinkedIn's Attic 3.2k Jan 4, 2023
MyLayout is a simple and easy objective-c framework for iOS view layout

MyLayout is a powerful iOS UI framework implemented by Objective-C. It integrates the functions with Android Layout,iOS AutoLayout,SizeClass, HTML CSS float and flexbox and bootstrap. So you can use LinearLayout,RelativeLayout,FrameLayout,TableLayout,FlowLayout,FloatLayout,PathLayout,GridLayout,LayoutSizeClass to build your App 自动布局 UIView UITableView UICollectionView RTL

欧阳大哥2013 4.2k Dec 30, 2022
A Code challenge I solved leveraging a lot on Composite collection view layout written in swift

AsthmApp Mobile app designed as a support aid for people with Asthma Accounts Google and Firebase [email protected] dICerytiMPSI Facebook asthmp.ap

null 0 Dec 13, 2021
A Code challenge I solved leveraging a lot on Composite collection view layout...written in swift

Space44 Code Challenge Space44 Code Challenge iOS application for Space 44 hiring process, it leverages on Image download and composite collection vie

null 0 Dec 16, 2021
A flexible collection view with proper horizontal layout flow

FlexCollection A very simple flexible collection view using SwiftUI that automat

null 1 Dec 29, 2021
A grid layout view for SwiftUI

Update July 2020 - latest SwiftUI now has built-in components to do this, which should be used instead. FlowStack FlowStack is a SwiftUI component for

John Susek 147 Nov 10, 2022
BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift!

BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift! Deprecated BrickKit is being phased out at Wayfair, and the

Wayfair Tech – Archive 608 Sep 15, 2022
Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

Extremely Fast views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainabl

layoutBox 2.1k Dec 22, 2022
A declarative Auto Layout DSL for Swift :iphone::triangular_ruler:

Cartography ?? ?? Using Cartography, you can set up your Auto Layout constraints in declarative code and without any stringly typing! In short, it all

Robb Böhnke 7.3k Jan 4, 2023
An easy way to create and layout UI components for iOS (Swift version).

Introduction Cupcake is a framework that allow you to easily create and layout UI components for iOS 8.0+. It use chaining syntax and provides some fr

nerdycat 288 Oct 9, 2022
Auto Layout made easy

EasyPeasy is a Swift framework that lets you create Auto Layout constraints programmatically without headaches and never ending boilerplate code. Besi

Carlos Vidal 1.9k Dec 23, 2022