From 881bcb72499a20ea924f80dc8e3f1057f17494ed Mon Sep 17 00:00:00 2001 From: Tyler Fox Date: Mon, 30 Dec 2013 15:20:50 -0800 Subject: [PATCH] Expose new generic methods to constrain different types of attributes across 2 views - Adjust the enums of ALEdge, ALDimension, and ALAxis to be unique (and additionally to match up with their NSLayoutAttribute counterparts) - Add new APIs that allow any combination of ALAttributes on 2 views to be constrained - Organize the source a bit more - Add a new example to the demo project that uses the new generic ALAttribute methods - Bump version number to v1.1 --- Example/Example/ALViewController.m | 63 ++++-- README.md | 9 +- Source/UIView+AutoLayout.h | 103 ++++++--- Source/UIView+AutoLayout.m | 348 +++++++++++++++++++++-------- 4 files changed, 374 insertions(+), 149 deletions(-) diff --git a/Example/Example/ALViewController.m b/Example/Example/ALViewController.m index 1aab6ae..297d984 100644 --- a/Example/Example/ALViewController.m +++ b/Example/Example/ALViewController.m @@ -16,6 +16,7 @@ typedef NS_ENUM(NSInteger, ExampleConstraintDemo) { ExampleConstraintDemo4, ExampleConstraintDemo5, ExampleConstraintDemo6, + ExampleConstraintDemo7, ExampleConstraintDemoCount }; @@ -225,15 +226,40 @@ - (void)setupDemo4 [self.orangeView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0f]; } +/** + Demonstrates: + - Everything from Demo 4, and... + - Using leading/trailing edge attributes instead of left/right + */ +- (void)setupDemo5 +{ + [self.redView autoSetDimension:ALDimensionHeight toSize:44.0f]; + [self.blueView autoMatchDimension:ALDimensionHeight toDimension:ALDimensionHeight ofView:self.redView]; + + [self.redView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:20.0f]; + [self.redView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f]; + + [self.blueView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:20.0f]; + [self.blueView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f]; + + [self.blueView autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:self.redView withOffset:10.0f]; + [self.blueView autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.redView withMultiplier:3.0f]; + + [self.orangeView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.blueView withOffset:20.0f]; + [self.orangeView autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self.redView withOffset:20.0]; + [self.orangeView autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:self.blueView withOffset:-10.0]; + [self.orangeView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0f]; +} + /** Demonstrates: - Looping over subviews to apply constraints between them - Setting a priority less than required for specific constraints - Specifying an inequality constraint that competes with the lower priority constraints - --> the orange view will maintain at least 10 points of spacing to the bottom of its superview (required constraint), - and this may require reducing its height (breaking the lower priority constraint) + --> the orange view will maintain at least 10 points of spacing to the bottom of its superview (required constraint), + and this may require reducing its height (breaking the lower priority constraint) */ -- (void)setupDemo5 +- (void)setupDemo6 { [self.blueView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:10.0f]; [self.blueView autoSetDimensionsToSize:CGSizeMake(25.0f, 10.0f)]; @@ -262,29 +288,15 @@ - (void)setupDemo5 /** Demonstrates: - - Achieving a common layout scenario for content (e.g. an image view, title label, and body text) - - Matching the widths of two views using a multiplier - - Pinning views to each other and to the superview to maintain padding and insets - - Using leading/trailing constraints instead of left/right + - Applying a constraint across different types of attributes */ -- (void)setupDemo6 +- (void)setupDemo7 { - [self.redView autoSetDimension:ALDimensionHeight toSize:44.0f]; - [self.blueView autoMatchDimension:ALDimensionHeight toDimension:ALDimensionHeight ofView:self.redView]; - - [self.redView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:20.0f]; - [self.redView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f]; - - [self.blueView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:20.0f]; - [self.blueView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f]; - - [self.blueView autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:self.redView withOffset:10.0f]; - [self.blueView autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.redView withMultiplier:3.0f]; - - [self.orangeView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.blueView withOffset:20.0f]; - [self.orangeView autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:self.redView withOffset:20.0]; - [self.orangeView autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:self.blueView withOffset:-10.0]; - [self.orangeView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0f]; + [self.redView autoCenterInSuperview]; + [self.redView autoSetDimensionsToSize:CGSizeMake(100.0f, 250.0f)]; + + [self.orangeView autoSetDimensionsToSize:CGSizeMake(50.0f, 50.0f)]; + [self.orangeView autoConstrainAttribute:ALAxisHorizontal toAttribute:ALEdgeTop ofView:self.redView]; } @@ -328,6 +340,9 @@ - (void)setupConstraintsForCurrentDemo case ExampleConstraintDemo6: [self setupDemo6]; break; + case ExampleConstraintDemo7: + [self setupDemo7]; + break; default: self.constraintDemo = ExampleConstraintDemoReset; break; diff --git a/README.md b/README.md index 531a57c..dc29e9a 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,11 @@ UIView+AutoLayout provides a developer-friendly interface for the vast majority API Cheat Sheet --------------- -This is just a handy overview of the primary methods. Check out the [header file](https://github.com/smileyborg/UIView-AutoLayout/blob/master/Source/UIView%2BAutoLayout.h) for the full API and documentation. - -*A couple notes:* +This is just a handy overview of the core API methods. Check out the [header file](https://github.com/smileyborg/UIView-AutoLayout/blob/master/Source/UIView%2BAutoLayout.h) for the full API and documentation. A couple notes: * *All of the API methods begin with `auto...` for easy autocompletion!* * *All methods that generate constraints also automatically add the constraint(s) to the correct view, then return the newly created constraint(s) for you to optionally store for later adjustment or removal.* +* *Many methods below also have a variant which includes a `relation:` parameter to make the constraint an inequality. **UIView** @@ -26,9 +25,9 @@ This is just a handy overview of the primary methods. Check out the [header file * \- autoPinEdge(s)ToSuperviewEdge(s):withInset(s): * \- autoPinEdge:toEdge:ofView:(withOffset:) * \- autoAlignAxis:toSameAxisOfView:(withOffset:) -* \- autoMatchDimension:toDimension:ofView:(withOffset:) -* \- autoMatchDimension:toDimension:ofView:(withMultiplier:) +* \- autoMatchDimension:toDimension:ofView:(withOffset:)(withMultiplier:) * \- autoSetDimension(s)ToSize: +* \- autoConstrainAttribute:toAttribute:ofView:(withOffset:)(withMultiplier:) * \- autoPinToTopLayoutGuideOfViewController:withInset: * \- autoPinToBottomLayoutGuideOfViewController:withInset: diff --git a/Source/UIView+AutoLayout.h b/Source/UIView+AutoLayout.h index 3a16656..cf9c172 100755 --- a/Source/UIView+AutoLayout.h +++ b/Source/UIView+AutoLayout.h @@ -1,6 +1,6 @@ // // UIView+AutoLayout.h -// v1.0.0 +// v1.1.0 // https://github.com/smileyborg/UIView-AutoLayout // // Copyright (c) 2012 Richard Turton @@ -29,24 +29,26 @@ #import +#pragma mark ALAttributes + typedef NS_ENUM(NSInteger, ALEdge) { - ALEdgeTop = 0, // the top edge of the view - ALEdgeLeft, // the left edge of the view - ALEdgeBottom, // the bottom edge of the view - ALEdgeRight, // the right edge of the view - ALEdgeLeading, // the leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic) - ALEdgeTrailing // the trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic) + ALEdgeLeft = NSLayoutAttributeLeft, // the left edge of the view + ALEdgeRight = NSLayoutAttributeRight, // the right edge of the view + ALEdgeTop = NSLayoutAttributeTop, // the top edge of the view + ALEdgeBottom = NSLayoutAttributeBottom, // the bottom edge of the view + ALEdgeLeading = 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) + ALEdgeTrailing = 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) }; -typedef NS_ENUM(NSInteger, ALAxis) { - ALAxisHorizontal = 0, // a horizontal line through the center of the view - ALAxisVertical, // a vertical line through the center of the view - ALAxisBaseline // a horizontal line at the text baseline (not applicable to all views) +typedef NS_ENUM(NSInteger, ALDimension) { + ALDimensionWidth = NSLayoutAttributeWidth, // the width of the view + ALDimensionHeight = NSLayoutAttributeHeight // the height of the view }; -typedef NS_ENUM(NSInteger, ALDimension) { - ALDimensionWidth = 0, // the width of the view - ALDimensionHeight // the height of the view +typedef NS_ENUM(NSInteger, ALAxis) { + ALAxisVertical = NSLayoutAttributeCenterX, // a vertical line through the center of the view + ALAxisHorizontal = NSLayoutAttributeCenterY, // a horizontal line through the center of the view + ALAxisBaseline = NSLayoutAttributeBaseline // a horizontal line at the text baseline (not applicable to all views) }; typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UIView+AutoLayout category API @@ -69,13 +71,15 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (instancetype)initForAutoLayout; -#pragma mark Auto Layout Convenience Methods +#pragma mark Set Constraint Priority /** Sets the constraint priority to the given value for all constraints created using the UIView+AutoLayout category API within the given constraints block. NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added using the SDK directly within the block! */ + (void)autoSetPriority:(UILayoutPriority)priority forConstraints:(ALConstraintsBlock)block; +#pragma mark Remove Constraints + /** Removes the given constraint from the view it has been added to. */ + (void)autoRemoveConstraint:(NSLayoutConstraint *)constraint; @@ -103,26 +107,16 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints; +#pragma mark Center in Superview + /** Centers the view in its superview. */ - (NSArray *)autoCenterInSuperview; -/** DEPRECATED, will be removed at some point in the future. Use -[autoAlignAxisToSuperviewAxis:] instead. - (This method has simply been renamed due to confusion. The replacement method works identically.) - Centers the view along the given axis (horizontal or vertical) within its superview. */ -- (NSLayoutConstraint *)autoCenterInSuperviewAlongAxis:(ALAxis)axis __attribute__((deprecated)); - /** Aligns the view to the same axis of its superview. */ - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis; -/** DEPRECATED, will be removed at some point in the future. - Pins the given center axis of the view to a fixed position (X or Y value, depending on axis) in the superview. */ -- (NSLayoutConstraint *)autoPinCenterAxis:(ALAxis)axis toPositionInSuperview:(CGFloat)value __attribute__((deprecated)); - -/** DEPRECATED, will be removed at some point in the future. Use -[autoPinEdgeToSuperviewEdge:withInset:] instead. - Pins the given edge of the view to a fixed position (X or Y value, depending on edge) in the superview. */ -- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toPositionInSuperview:(CGFloat)value __attribute__((deprecated)); - +#pragma mark Pin Edges to Superview /** Pins the given edge of the view to the same edge of the superview with an inset. */ - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset; @@ -134,6 +128,8 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(UIEdgeInsets)insets; +#pragma mark Pin Edges + /** Pins an edge of the view to a given edge of another view. */ - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(UIView *)peerView; @@ -144,6 +140,8 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(UIView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; +#pragma mark Align Axes + /** Aligns an axis of the view to the same axis of another view. */ - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(UIView *)peerView; @@ -151,6 +149,8 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(UIView *)peerView withOffset:(CGFloat)offset; +#pragma mark Match Dimensions + /** Matches a dimension of the view to a given dimension of another view. */ - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(UIView *)peerView; @@ -167,6 +167,8 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(UIView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; +#pragma mark Set Dimensions + /** Sets the view to a specific size. */ - (NSArray *)autoSetDimensionsToSize:(CGSize)size; @@ -177,12 +179,48 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation; +#pragma mark Constrain Any Attributes + +/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view. */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(UIView *)peerView; + +/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset. */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(UIView *)peerView withOffset:(CGFloat)offset; + +/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset as a maximum or minimum. */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(UIView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; + +/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier. */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(UIView *)peerView withMultiplier:(CGFloat)multiplier; + +/** Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier as a maximum or minimum. */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)attribute toAttribute:(NSInteger)toAttribute ofView:(UIView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; + + +#pragma mark Pin to Layout Guides + /** Pins the top edge of the view to the top layout guide of the given view controller with an inset. */ - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; /** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset. */ - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; + +#pragma mark Deprecated API Methods + +/** DEPRECATED as of v1.1, will be removed at some point in the future. Use -[autoAlignAxisToSuperviewAxis:] instead. + (This method has simply been renamed due to confusion. The replacement method works identically.) + Centers the view along the given axis (horizontal or vertical) within its superview. */ +- (NSLayoutConstraint *)autoCenterInSuperviewAlongAxis:(ALAxis)axis __attribute__((deprecated)); + +/** DEPRECATED as of v1.1, will be removed at some point in the future. Use -[autoConstrainAttribute:toAttribute:ofView:withOffset:] instead. + Pins the given center axis of the view to a fixed position (X or Y value, depending on axis) in the superview. */ +- (NSLayoutConstraint *)autoPinCenterAxis:(ALAxis)axis toPositionInSuperview:(CGFloat)value __attribute__((deprecated)); + +/** DEPRECATED as of v1.1, will be removed at some point in the future. Use -[autoPinEdgeToSuperviewEdge:withInset:] instead. + Pins the given edge of the view to a fixed position (X or Y value, depending on edge) in the superview. */ +- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toPositionInSuperview:(CGFloat)value __attribute__((deprecated)); + @end @@ -193,6 +231,9 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI */ @interface NSArray (AutoLayout) + +#pragma mark Constrain Multiple Views + /** Aligns views in this array to one another along a given edge. */ - (NSArray *)autoAlignViewsToEdge:(ALEdge)edge; @@ -206,10 +247,12 @@ typedef void(^ALConstraintsBlock)(void); // a block of method calls to the UI - (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size; -/** Distributes the views in this array equally along the selected axis. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */ +#pragma mark Distribute Multiple Views + +/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */ - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat)spacing alignment:(NSLayoutFormatOptions)alignment; -/** Distributes the views in this array equally along the selected axis. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */ +/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */ - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSize:(CGFloat)size alignment:(NSLayoutFormatOptions)alignment; @end diff --git a/Source/UIView+AutoLayout.m b/Source/UIView+AutoLayout.m index ae743c3..b68c429 100755 --- a/Source/UIView+AutoLayout.m +++ b/Source/UIView+AutoLayout.m @@ -1,6 +1,6 @@ // // UIView+AutoLayout.m -// v1.0.0 +// v1.1.0 // https://github.com/smileyborg/UIView-AutoLayout // // Copyright (c) 2012 Richard Turton @@ -34,6 +34,7 @@ @implementation UIView (AutoLayout) + #pragma mark Factory & Initializer Methods /** @@ -58,7 +59,8 @@ - (instancetype)initForAutoLayout return self; } -#pragma mark Auto Layout Convenience Methods + +#pragma mark Set Constraint Priority /** A global variable that determines the priority of all constraints created and added by this category. @@ -88,6 +90,9 @@ + (void)autoSetPriority:(UILayoutPriority)priority forConstraints:(ALConstraints _globalConstraintPriority = UILayoutPriorityRequired; } + +#pragma mark Remove Constraints + /** Removes the given constraint from the view it has been added to. @@ -194,6 +199,9 @@ - (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraint } } + +#pragma mark Center in Superview + /** Centers the view in its superview. @@ -207,20 +215,6 @@ - (NSArray *)autoCenterInSuperview return constraints; } -/** - DEPRECATED, will be removed at some point in the future. Use -[autoAlignAxisToSuperviewAxis:] instead. - (This method has simply been renamed due to confusion. The replacement method works identically.) - - Centers the view along the given axis (horizontal or vertical) within its superview. - - @param axis The axis of this view and of its superview to center on. - @return The constraint added. - */ -- (NSLayoutConstraint *)autoCenterInSuperviewAlongAxis:(ALAxis)axis -{ - return [self autoAlignAxisToSuperviewAxis:axis]; -} - /** Aligns the view to the same axis of its superview. @@ -237,64 +231,8 @@ - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis return constraint; } -/** - DEPRECATED, will be removed at some point in the future. - - Pins the given center axis of the view to a fixed position (X or Y value, depending on axis) in the superview. - - @param axis The center axis of this view to pin. - @param value The x (if horizontal axis) or y (if vertical axis) absolute position in the superview to pin this view at. - @return The constraint added. - */ -- (NSLayoutConstraint *)autoPinCenterAxis:(ALAxis)axis toPositionInSuperview:(CGFloat)value -{ - UIView *superview = self.superview; - NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); - NSLayoutAttribute attribute = [UIView al_attributeForAxis:axis]; - NSLayoutConstraint *constraint = nil; - if (axis == ALAxisVertical) { - constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.0f constant:value]; - } - else { - constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0f constant:value]; - } - [superview al_addConstraintUsingGlobalPriority:constraint]; - return constraint; -} -/** - DEPRECATED, will be removed at some point in the future. Use -[autoPinEdgeToSuperviewEdge:withInset:] instead. - - Pins the given edge of the view to a fixed position (X or Y value, depending on edge) in the superview. - - @param edge The edge of this view to pin. - @param value The x (if left or right edge) or y (if top or bottom edge) absolute position in the superview to pin this view at. - @return The constraint added. - */ -- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toPositionInSuperview:(CGFloat)value -{ - UIView *superview = self.superview; - NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); - ALEdge superviewEdge; - switch (edge) { - case ALEdgeLeft: - case ALEdgeRight: - superviewEdge = ALEdgeLeft; - break; - case ALEdgeTop: - case ALEdgeBottom: - superviewEdge = ALEdgeTop; - break; - case ALEdgeLeading: - case ALEdgeTrailing: - superviewEdge = ALEdgeLeading; - break; - default: - NSAssert(nil, @"Not a valid edge."); - break; - } - return [self autoPinEdge:edge toEdge:superviewEdge ofView:superview withOffset:value]; -} +#pragma mark Pin Edges to Superview /** Pins the given edge of the view to the same edge of the superview with an inset. @@ -350,6 +288,9 @@ - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(UIEdgeInsets)insets return constraints; } + +#pragma mark Pin Edges + /** Pins an edge of the view to a given edge of another view. @@ -397,6 +338,9 @@ - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(U return constraint; } + +#pragma mark Align Axes + /** Aligns an axis of the view to the same axis of another view. @@ -426,6 +370,9 @@ - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(UIView *)pe return constraint; } + +#pragma mark Match Dimensions + /** Matches a dimension of the view to a given dimension of another view. @@ -507,6 +454,9 @@ - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(A return constraint; } + +#pragma mark Set Dimensions + /** Sets the view to a specific size. @@ -549,6 +499,98 @@ - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat) return constraint; } + +#pragma mark Constrain Any Attributes + +/** + Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view. + This method can be used to constrain different types of attributes across two views. + + @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain. + @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to. + @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(UIView *)peerView +{ + return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withOffset:0.0f]; +} + +/** + Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset. + This method can be used to constrain different types of attributes across two views. + + @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain. + @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to. + @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view. + @param offset The offset between the attribute of this view and the attribute of the peer view. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(UIView *)peerView withOffset:(CGFloat)offset +{ + return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withOffset:offset relation:NSLayoutRelationEqual]; +} + +/** + Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with an offset as a maximum or minimum. + This method can be used to constrain different types of attributes across two views. + + @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain. + @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to. + @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view. + @param offset The offset between the attribute of this view and the attribute of the peer view. + @param relation Whether the offset should be at least, at most, or exactly equal to the given value. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(UIView *)peerView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation +{ + UIView *superview = [self al_commonSuperviewWithView:peerView]; + NSLayoutAttribute attribute = [UIView al_attributeForALAttribute:ALAttribute]; + NSLayoutAttribute toAttribute = [UIView al_attributeForALAttribute:toALAttribute]; + NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:1.0f constant:offset]; + [superview al_addConstraintUsingGlobalPriority:constraint]; + return constraint; +} + +/** + Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier. + This method can be used to constrain different types of attributes across two views. + + @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain. + @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to. + @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view. + @param multiplier The multiplier between the attribute of this view and the attribute of the peer view. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(UIView *)peerView withMultiplier:(CGFloat)multiplier +{ + return [self autoConstrainAttribute:ALAttribute toAttribute:toALAttribute ofView:peerView withMultiplier:multiplier relation:NSLayoutRelationEqual]; +} + +/** + Constrains an attribute (any ALEdge, ALAxis, or ALDimension) of the view to a given attribute of another view with a multiplier as a maximum or minimum. + This method can be used to constrain different types of attributes across two views. + + @param ALAttribute Any ALEdge, ALAxis, or ALDimension of this view to constrain. + @param toALAttribute Any ALEdge, ALAxis, or ALDimension of the peer view to constrain to. + @param peerView The peer view to constrain to. Must be in the same view hierarchy as this view. + @param multiplier The multiplier between the attribute of this view and the attribute of the peer view. + @param relation Whether the multiplier should be at least, at most, or exactly equal to the given value. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoConstrainAttribute:(NSInteger)ALAttribute toAttribute:(NSInteger)toALAttribute ofView:(UIView *)peerView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation +{ + UIView *superview = [self al_commonSuperviewWithView:peerView]; + NSLayoutAttribute attribute = [UIView al_attributeForALAttribute:ALAttribute]; + NSLayoutAttribute toAttribute = [UIView al_attributeForALAttribute:toALAttribute]; + NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:relation toItem:peerView attribute:toAttribute multiplier:multiplier constant:0.0f]; + [superview al_addConstraintUsingGlobalPriority:constraint]; + return constraint; +} + + +#pragma mark Pin to Layout Guides + /** Pins the top edge of the view to the top layout guide of the given view controller with an inset. For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the top edge of @@ -590,6 +632,82 @@ - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewContro } +#pragma mark Deprecated API Methods + +/** + DEPRECATED, will be removed at some point in the future. Use -[autoAlignAxisToSuperviewAxis:] instead. + (This method has simply been renamed due to confusion. The replacement method works identically.) + + Centers the view along the given axis (horizontal or vertical) within its superview. + + @param axis The axis of this view and of its superview to center on. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoCenterInSuperviewAlongAxis:(ALAxis)axis +{ + return [self autoAlignAxisToSuperviewAxis:axis]; +} + +/** + DEPRECATED, will be removed at some point in the future. Use -[autoConstrainAttribute:toAttribute:ofView:withOffset:] instead. + + Pins the given center axis of the view to a fixed position (X or Y value, depending on axis) in the superview. + + @param axis The center axis of this view to pin. + @param value The x (if horizontal axis) or y (if vertical axis) absolute position in the superview to pin this view at. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoPinCenterAxis:(ALAxis)axis toPositionInSuperview:(CGFloat)value +{ + UIView *superview = self.superview; + NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); + NSLayoutAttribute attribute = [UIView al_attributeForAxis:axis]; + NSLayoutConstraint *constraint = nil; + if (axis == ALAxisVertical) { + constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.0f constant:value]; + } + else { + constraint = [NSLayoutConstraint constraintWithItem:self attribute:attribute relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0f constant:value]; + } + [superview al_addConstraintUsingGlobalPriority:constraint]; + return constraint; +} + +/** + DEPRECATED, will be removed at some point in the future. Use -[autoPinEdgeToSuperviewEdge:withInset:] instead. + + Pins the given edge of the view to a fixed position (X or Y value, depending on edge) in the superview. + + @param edge The edge of this view to pin. + @param value The x (if left or right edge) or y (if top or bottom edge) absolute position in the superview to pin this view at. + @return The constraint added. + */ +- (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toPositionInSuperview:(CGFloat)value +{ + UIView *superview = self.superview; + NSAssert(superview, @"View's superview must not be nil.\nView: %@", self); + ALEdge superviewEdge; + switch (edge) { + case ALEdgeLeft: + case ALEdgeRight: + superviewEdge = ALEdgeLeft; + break; + case ALEdgeTop: + case ALEdgeBottom: + superviewEdge = ALEdgeTop; + break; + case ALEdgeLeading: + case ALEdgeTrailing: + superviewEdge = ALEdgeLeading; + break; + default: + NSAssert(nil, @"Not a valid edge."); + break; + } + return [self autoPinEdge:edge toEdge:superviewEdge ofView:superview withOffset:value]; +} + + #pragma mark Internal Helper Methods /** @@ -613,20 +731,20 @@ - (void)al_addConstraintUsingGlobalPriority:(NSLayoutConstraint *)constraint */ + (NSLayoutAttribute)al_attributeForEdge:(ALEdge)edge { - NSLayoutAttribute attribute; + NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute; switch (edge) { - case ALEdgeTop: - attribute = NSLayoutAttributeTop; - break; case ALEdgeLeft: attribute = NSLayoutAttributeLeft; break; - case ALEdgeBottom: - attribute = NSLayoutAttributeBottom; - break; case ALEdgeRight: attribute = NSLayoutAttributeRight; break; + case ALEdgeTop: + attribute = NSLayoutAttributeTop; + break; + case ALEdgeBottom: + attribute = NSLayoutAttributeBottom; + break; case ALEdgeLeading: attribute = NSLayoutAttributeLeading; break; @@ -634,7 +752,7 @@ + (NSLayoutAttribute)al_attributeForEdge:(ALEdge)edge attribute = NSLayoutAttributeTrailing; break; default: - NSAssert(nil, @"Not a valid edge."); + NSAssert(nil, @"Not a valid ALEdge."); break; } return attribute; @@ -647,19 +765,19 @@ + (NSLayoutAttribute)al_attributeForEdge:(ALEdge)edge */ + (NSLayoutAttribute)al_attributeForAxis:(ALAxis)axis { - NSLayoutAttribute attribute; + NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute; switch (axis) { - case ALAxisHorizontal: - attribute = NSLayoutAttributeCenterY; - break; case ALAxisVertical: attribute = NSLayoutAttributeCenterX; break; + case ALAxisHorizontal: + attribute = NSLayoutAttributeCenterY; + break; case ALAxisBaseline: attribute = NSLayoutAttributeBaseline; break; default: - NSAssert(nil, @"Not a valid axis."); + NSAssert(nil, @"Not a valid ALAxis."); break; } return attribute; @@ -672,7 +790,7 @@ + (NSLayoutAttribute)al_attributeForAxis:(ALAxis)axis */ + (NSLayoutAttribute)al_attributeForDimension:(ALDimension)dimension { - NSLayoutAttribute attribute; + NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute; switch (dimension) { case ALDimensionWidth: attribute = NSLayoutAttributeWidth; @@ -681,7 +799,51 @@ + (NSLayoutAttribute)al_attributeForDimension:(ALDimension)dimension attribute = NSLayoutAttributeHeight; break; default: - NSAssert(nil, @"Not a valid dimension."); + NSAssert(nil, @"Not a valid ALDimension."); + break; + } + return attribute; +} + ++ (NSLayoutAttribute)al_attributeForALAttribute:(NSInteger)ALAttribute +{ + NSLayoutAttribute attribute = NSLayoutAttributeNotAnAttribute; + switch (ALAttribute) { + case ALEdgeLeft: + attribute = NSLayoutAttributeLeft; + break; + case ALEdgeRight: + attribute = NSLayoutAttributeRight; + break; + case ALEdgeTop: + attribute = NSLayoutAttributeTop; + break; + case ALEdgeBottom: + attribute = NSLayoutAttributeBottom; + break; + case ALEdgeLeading: + attribute = NSLayoutAttributeLeading; + break; + case ALEdgeTrailing: + attribute = NSLayoutAttributeTrailing; + break; + case ALDimensionWidth: + attribute = NSLayoutAttributeWidth; + break; + case ALDimensionHeight: + attribute = NSLayoutAttributeHeight; + break; + case ALAxisVertical: + attribute = NSLayoutAttributeCenterX; + break; + case ALAxisHorizontal: + attribute = NSLayoutAttributeCenterY; + break; + case ALAxisBaseline: + attribute = NSLayoutAttributeBaseline; + break; + default: + NSAssert(nil, @"Not a valid ALAttribute."); break; } return attribute; @@ -769,6 +931,9 @@ - (NSLayoutConstraint *)al_alignToView:(UIView *)peerView withOption:(NSLayoutFo @implementation NSArray (AutoLayout) + +#pragma mark Constrain Multiple Views + /** Aligns views in this array to one another along a given edge. Note: This array must contain at least 2 views, and all views must share a common superview. @@ -862,8 +1027,11 @@ - (NSArray *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size return constraints; } + +#pragma mark Distribute Multiple Views + /** - Distributes the views in this array equally along the selected axis. + Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. @param axis The axis along which to distribute the subviews. @@ -916,7 +1084,7 @@ - (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis withFixedSpacing:(CGFloat } /** - Distributes the views in this array equally along the selected axis. + Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. @param axis The axis along which to distribute the subviews.