Skip to content

Instantly share code, notes, and snippets.

@dgyesbreghs
Created October 13, 2018 07:00
Show Gist options
  • Save dgyesbreghs/27c304170cd9e293c38ccb67f18b95fa to your computer and use it in GitHub Desktop.
Save dgyesbreghs/27c304170cd9e293c38ccb67f18b95fa to your computer and use it in GitHub Desktop.
//
// UIView+LayoutConstraints.h
// UIView+LayoutConstraints
//
// Created by Dylan Gyesbreghs on 02/02/2018.
//
#import <PureLayout.h>
typedef NS_ENUM(NSInteger, ALAnchor) {
ALAnchorLeft = NSLayoutAttributeLeft, // the left edge of the view
ALAnchorRight = NSLayoutAttributeRight, // the right edge of the view
ALAnchorTop = NSLayoutAttributeTop, // the top edge of the view
ALAnchorBottom = NSLayoutAttributeBottom, // the bottom edge of the view
ALAnchorLeading = NSLayoutAttributeLeading, // the leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic)
ALAnchorTrailing = NSLayoutAttributeTrailing // the trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic)
};
static inline ALEdge convertAnchor(ALAnchor anchor) {
switch (anchor) {
case ALAnchorLeft:
return ALEdgeLeft;
case ALAnchorRight:
return ALEdgeRight;
case ALAnchorTop:
return ALEdgeTop;
case ALAnchorBottom:
return ALEdgeBottom;
case ALAnchorLeading:
return ALEdgeLeading;
case ALAnchorTrailing:
return ALEdgeTrailing;
}
}
@interface UIView (LayoutConstraints)
//** Pins the left and right edge depending on the orientation so everything is correct for iPhone X
- (void)createLandscapePhoneConstraintWithArray:(NSMutableArray *)constraints;
#pragma mark - Superview Helpers
/** Pins the given edge of the view to the same edge of the superview with an inset. */
- (NSLayoutConstraint *)autoPinAnchorToSuperviewAnchor:(ALAnchor)anchor withConstant:(CGFloat)constant;
/** Pins the edges of the view to the edges of its superview with edge insets zero. */
- (NSArray *)autoPinAnchorsToSuperviewAnchors;
/** Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. */
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithExcludingAnchor:(ALAnchor)anchor;
/** Pins the edges of the view to the edges of its superview with the given edge insets. */
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithInsets:(UIEdgeInsets)insets;
/** Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. */
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithInsets:(UIEdgeInsets)insets excludingAnchor:(ALAnchor)anchor;
#pragma mark - Dimensions Helpers
/** Sets the view to a specific size. */
- (NSArray *)autoSetDimensionsToSize:(CGSize)size;
/** Sets the given dimension of the view to a specific size. */
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size;
/** Matches a dimension of the view to a given dimension of another view. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension ofView:(UIView *)peerView;
///** Matches a dimension of the view to a given dimension of another view with an offset. */
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension ofView:(UIView *)peerView withOffset:(CGFloat)offset;
/** Return the layoutGuide for the correct iOS Version
< iOS 11 -> Margin Area Guide
>= iOS 11 -> Safe Area Guide
*/
- (UILayoutGuide *)layoutGuide;
@end
//
// UIView+LayoutConstraints.m
// UIView+LayoutConstraints
//
// Created by Dylan Gyesbreghs on 02/02/2018.
//
#import "UIView+LayoutConstraints.h"
@implementation UIView (LayoutConstraints)
- (void)createLandscapePhoneConstraintWithArray:(NSMutableArray *)constraints {
if (constraints == nil) {
constraints = [NSMutableArray arrayWithCapacity:2];
}
[NSLayoutConstraint deactivateConstraints:constraints];
[constraints removeAllObjects];
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
[constraints addObjectsFromArray:@[[self autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:0],[self autoPinAnchorToSuperviewAnchor:ALAnchorLeft withConstant:0]]];
} else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft){
[constraints addObjectsFromArray:@[[self autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:0],[self autoPinAnchorToSuperviewAnchor:ALAnchorRight withConstant:0]]];
} else {
[constraints addObjectsFromArray:@[[self autoPinAnchorToSuperviewAnchor:ALAnchorRight withConstant:0], [self autoPinAnchorToSuperviewAnchor:ALAnchorLeft withConstant:0]]];
}
}
#pragma mark - Superview Helpers
- (NSLayoutConstraint *)autoPinAnchorToSuperviewAnchor:(ALAnchor)anchor withConstant:(CGFloat)constant;
{
if (![self respondsToSelector:@selector(safeAreaLayoutGuide)]) {
return [self autoPinEdgeToSuperviewEdge:convertAnchor(anchor) withInset:constant];
}
NSLayoutConstraint *constraint;
if (anchor == ALAnchorBottom || anchor == ALAnchorRight || anchor == ALAnchorTrailing) {
// The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets
constant = -constant;
}
UILayoutGuide *layoutGuide = self.superview.layoutGuide;
switch (anchor) {
case ALAnchorTop:
constraint = [self.topAnchor constraintEqualToAnchor:layoutGuide.topAnchor
constant:constant];
break;
case ALAnchorBottom:
constraint = [self.bottomAnchor constraintEqualToAnchor:layoutGuide.bottomAnchor
constant:constant];
break;
case ALAnchorLeading:
constraint = [self.leadingAnchor constraintEqualToAnchor:layoutGuide.leadingAnchor
constant:constant];
break;
case ALAnchorTrailing:
constraint = [self.trailingAnchor constraintEqualToAnchor:layoutGuide.trailingAnchor
constant:constant];
break;
case ALAnchorLeft:
constraint = [self.leftAnchor constraintEqualToAnchor:layoutGuide.leftAnchor
constant:constant];
break;
case ALAnchorRight:
constraint = [self.rightAnchor constraintEqualToAnchor:layoutGuide.rightAnchor
constant:constant];
break;
}
constraint.active = YES;
return constraint;
}
- (NSArray *)autoPinAnchorsToSuperviewAnchors
{
return [self autoPinAnchorsToSuperviewAnchorsWithInsets:UIEdgeInsetsZero];
}
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithExcludingAnchor:(ALAnchor)anchor
{
return [self autoPinAnchorsToSuperviewAnchorsWithInsets:UIEdgeInsetsZero excludingAnchor:anchor];
}
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithInsets:(UIEdgeInsets)insets
{
NSMutableArray *constraints = [NSMutableArray new];
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorTop withConstant:insets.top]];
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorLeading withConstant:insets.left]];
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorBottom withConstant:insets.bottom]];
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorTrailing withConstant:insets.right]];
return constraints;
}
- (NSArray *)autoPinAnchorsToSuperviewAnchorsWithInsets:(UIEdgeInsets)insets excludingAnchor:(ALAnchor)anchor
{
NSMutableArray *constraints = [NSMutableArray new];
if (anchor != ALAnchorTop) {
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorTop withConstant:insets.top]];
}
if (anchor != ALAnchorLeading && anchor != ALAnchorLeft) {
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorLeading withConstant:insets.left]];
}
if (anchor != ALAnchorBottom) {
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorBottom withConstant:insets.bottom]];
}
if (anchor != ALAnchorTrailing && anchor != ALAnchorRight) {
[constraints addObject:[self autoPinAnchorToSuperviewAnchor:ALAnchorTrailing withConstant:insets.right]];
}
return constraints;
}
#pragma mark - Dimensions
- (NSArray *)autoSetDimensionsToSize:(CGSize)size
{
NSMutableArray *constraints = [NSMutableArray new];
[constraints addObject:[self autoSetDimension:ALDimensionWidth toSize:size.width]];
[constraints addObject:[self autoSetDimension:ALDimensionHeight toSize:size.height]];
return constraints;
}
- (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size
{
NSLayoutConstraint *constraint;
switch (dimension) {
case ALDimensionWidth:
constraint = [self.widthAnchor constraintEqualToConstant:size];
break;
case ALDimensionHeight:
constraint = [self.heightAnchor constraintEqualToConstant:size];
break;
}
constraint.active = YES;
return constraint;
}
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension ofView:(UIView *)peerView
{
return [self autoMatchDimension:dimension ofView:peerView withOffset:0];
}
- (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension ofView:(UIView *)peerView withOffset:(CGFloat)offset
{
NSLayoutConstraint *constraint;
switch (dimension) {
case ALDimensionWidth:
constraint = [self.widthAnchor constraintEqualToAnchor:peerView.layoutGuide.widthAnchor
constant:offset];
break;
case ALDimensionHeight:
constraint = [self.heightAnchor constraintEqualToAnchor:peerView.layoutGuide.heightAnchor
constant:offset];
break;
}
constraint.active = YES;
return constraint;
}
- (UILayoutGuide *)layoutGuide
{
if (@available(iOS 11, *)) {
return self.safeAreaLayoutGuide;
}
return self.layoutMarginsGuide;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment