PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/Source/ALView+PureLayout.m

https://gitlab.com/lisit1003/PureLayout
Objective C | 1088 lines | 530 code | 104 blank | 454 comment | 98 complexity | abb28b13d11707dc70e7ea9418c26db6 MD5 | raw file
  1. //
  2. // ALView+PureLayout.m
  3. // v2.0.4
  4. // https://github.com/smileyborg/PureLayout
  5. //
  6. // Copyright (c) 2012 Richard Turton
  7. // Copyright (c) 2013-2014 Tyler Fox
  8. //
  9. // This code is distributed under the terms and conditions of the MIT license.
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining a copy
  12. // of this software and associated documentation files (the "Software"), to
  13. // deal in the Software without restriction, including without limitation the
  14. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  15. // sell copies of the Software, and to permit persons to whom the Software is
  16. // furnished to do so, subject to the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be included in
  19. // all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  27. // IN THE SOFTWARE.
  28. //
  29. #import "ALView+PureLayout.h"
  30. #import "NSLayoutConstraint+PureLayout.h"
  31. #import "NSArray+PureLayout.h"
  32. #import "PureLayout+Internal.h"
  33. #pragma mark - ALView+PureLayout
  34. @implementation ALView (PureLayout)
  35. #pragma mark Factory & Initializer Methods
  36. /**
  37. Creates and returns a new view that does not convert the autoresizing mask into constraints.
  38. */
  39. + (instancetype)newAutoLayoutView
  40. {
  41. ALView *view = [self new];
  42. view.translatesAutoresizingMaskIntoConstraints = NO;
  43. return view;
  44. }
  45. /**
  46. Initializes and returns a new view that does not convert the autoresizing mask into constraints.
  47. */
  48. - (instancetype)initForAutoLayout
  49. {
  50. self = [self init];
  51. if (self) {
  52. self.translatesAutoresizingMaskIntoConstraints = NO;
  53. }
  54. return self;
  55. }
  56. #pragma mark Create Constraints Without Installing
  57. /**
  58. A global variable that stores a stack of arrays of constraints created without being immediately installed.
  59. When executing a constraints block passed into the +[autoCreateConstraintsWithoutInstalling:] method, a new
  60. mutable array is pushed onto this stack, and all constraints created with PureLayout in the block are added
  61. to this array. When the block finishes executing, the array is popped off this stack. Automatic constraint
  62. installation is prevented if this stack contains at least 1 array.
  63. NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
  64. */
  65. static NSMutableArray *_al_arraysOfCreatedConstraints = nil;
  66. /**
  67. Accessor for the global state that stores arrays of constraints created without being installed.
  68. */
  69. + (NSMutableArray *)al_arraysOfCreatedConstraints
  70. {
  71. if (!_al_arraysOfCreatedConstraints) {
  72. _al_arraysOfCreatedConstraints = [NSMutableArray new];
  73. }
  74. return _al_arraysOfCreatedConstraints;
  75. }
  76. /**
  77. Accessor for the current mutable array of constraints created without being immediately installed.
  78. */
  79. + (NSMutableArray *)al_currentArrayOfCreatedConstraints
  80. {
  81. return [[self al_arraysOfCreatedConstraints] lastObject];
  82. }
  83. /**
  84. Accessor for the global state that determines whether automatic constraint installation should be prevented.
  85. */
  86. + (BOOL)al_preventAutomaticConstraintInstallation
  87. {
  88. return [[self al_arraysOfCreatedConstraints] count] > 0;
  89. }
  90. /**
  91. Prevents constraints created in the given constraints block from being automatically installed (activated).
  92. The constraints created from calls to the PureLayout API in the block are returned in a single array.
  93. @param block A block of method calls to the PureLayout API that create constraints.
  94. @return An array of the constraints that were created from calls to the PureLayout API inside the block.
  95. */
  96. + (NSArray *)autoCreateConstraintsWithoutInstalling:(ALConstraintsBlock)block
  97. {
  98. NSAssert(block, @"The constraints block cannot be nil.");
  99. NSArray *createdConstraints = nil;
  100. if (block) {
  101. [[self al_arraysOfCreatedConstraints] addObject:[NSMutableArray new]];
  102. block();
  103. createdConstraints = [self al_currentArrayOfCreatedConstraints];
  104. [[self al_arraysOfCreatedConstraints] removeLastObject];
  105. }
  106. return createdConstraints;
  107. }
  108. #pragma mark Set Priority For Constraints
  109. /**
  110. A global variable that stores a stack of layout priorities to set on constraints.
  111. When executing a constraints block passed into the +[autoSetPriority:forConstraints:] method, the priority for
  112. that call is pushed onto this stack, and when the block finishes executing, that priority is popped off this
  113. stack. If this stack contains at least 1 priority, the priority at the top of the stack will be set for all
  114. constraints created by this library (even if automatic constraint installation is being prevented).
  115. NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
  116. */
  117. static NSMutableArray *_al_globalConstraintPriorities = nil;
  118. /**
  119. Accessor for the global stack of layout priorities.
  120. */
  121. + (NSMutableArray *)al_globalConstraintPriorities
  122. {
  123. if (!_al_globalConstraintPriorities) {
  124. _al_globalConstraintPriorities = [NSMutableArray new];
  125. }
  126. return _al_globalConstraintPriorities;
  127. }
  128. /**
  129. Returns the current layout priority to use for constraints.
  130. When executing a constraints block passed into +[autoSetPriority:forConstraints:], this will return
  131. the priority for the current block. Otherwise, the default Required priority is returned.
  132. */
  133. + (ALLayoutPriority)al_currentGlobalConstraintPriority
  134. {
  135. NSMutableArray *globalConstraintPriorities = [self al_globalConstraintPriorities];
  136. if ([globalConstraintPriorities count] == 0) {
  137. return ALLayoutPriorityRequired;
  138. }
  139. return [[globalConstraintPriorities lastObject] floatValue];
  140. }
  141. /**
  142. Accessor for the global state that determines if we're currently in the scope of a priority constraints block.
  143. */
  144. + (BOOL)al_isExecutingPriorityConstraintsBlock
  145. {
  146. return [[self al_globalConstraintPriorities] count] > 0;
  147. }
  148. /**
  149. Sets the constraint priority to the given value for all constraints created using the PureLayout
  150. API within the given constraints block.
  151. NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added
  152. without using the PureLayout API!
  153. @param priority The layout priority to be set on all constraints created in the constraints block.
  154. @param block A block of method calls to the PureLayout API that create and install constraints.
  155. */
  156. + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block
  157. {
  158. NSAssert(block, @"The constraints block cannot be nil.");
  159. if (block) {
  160. [[self al_globalConstraintPriorities] addObject:@(priority)];
  161. block();
  162. [[self al_globalConstraintPriorities] removeLastObject];
  163. }
  164. }
  165. #pragma mark Set Identifier For Constraints
  166. #if __PureLayout_MinBaseSDK_iOS_8_0
  167. /**
  168. A global variable that stores a stack of identifier strings to set on constraints.
  169. When executing a constraints block passed into the +[autoSetIdentifier:forConstraints:] method, the identifier for
  170. that call is pushed onto this stack, and when the block finishes executing, that identifier is popped off this
  171. stack. If this stack contains at least 1 identifier, the identifier at the top of the stack will be set for all
  172. constraints created by this library (even if automatic constraint installation is being prevented).
  173. NOTE: Access to this variable is not synchronized (and should only be done on the main thread).
  174. */
  175. static NSMutableArray *_al_globalConstraintIdentifiers = nil;
  176. /**
  177. Accessor for the global state of constraint identifiers.
  178. */
  179. + (NSMutableArray *)al_globalConstraintIdentifiers
  180. {
  181. if (!_al_globalConstraintIdentifiers) {
  182. _al_globalConstraintIdentifiers = [NSMutableArray new];
  183. }
  184. return _al_globalConstraintIdentifiers;
  185. }
  186. /**
  187. Returns the current identifier string to use for constraints.
  188. When executing a constraints block passed into +[autoSetIdentifier:forConstraints:], this will return
  189. the identifier for the current block. Otherwise, nil is returned.
  190. */
  191. + (NSString *)al_currentGlobalConstraintIdentifier
  192. {
  193. NSMutableArray *globalConstraintIdentifiers = [self al_globalConstraintIdentifiers];
  194. if ([globalConstraintIdentifiers count] == 0) {
  195. return nil;
  196. }
  197. return [globalConstraintIdentifiers lastObject];
  198. }
  199. /**
  200. Sets the identifier for all constraints created using the PureLayout API within the given constraints block.
  201. NOTE: This method will have no effect (and will NOT set the identifier) on constraints created or added
  202. without using the PureLayout API!
  203. @param identifier A string used to identify all constraints created in the constraints block.
  204. @param block A block of method calls to the PureLayout API that create and install constraints.
  205. */
  206. + (void)autoSetIdentifier:(NSString *)identifier forConstraints:(ALConstraintsBlock)block
  207. {
  208. NSAssert(block, @"The constraints block cannot be nil.");
  209. NSAssert(identifier, @"The identifier string cannot be nil.");
  210. if (block) {
  211. if (identifier) {
  212. [[self al_globalConstraintIdentifiers] addObject:identifier];
  213. }
  214. block();
  215. if (identifier) {
  216. [[self al_globalConstraintIdentifiers] removeLastObject];
  217. }
  218. }
  219. }
  220. #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */
  221. #pragma mark Center in Superview
  222. /**
  223. Centers the view in its superview.
  224. @return An array of constraints added.
  225. */
  226. - (NSArray *)autoCenterInSuperview
  227. {
  228. NSMutableArray *constraints = [NSMutableArray new];
  229. [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisHorizontal]];
  230. [constraints addObject:[self autoAlignAxisToSuperviewAxis:ALAxisVertical]];
  231. return constraints;
  232. }
  233. /**
  234. Aligns the view to the same axis of its superview.
  235. @param axis The axis of this view and of its superview to align.
  236. @return The constraint added.
  237. */
  238. - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis
  239. {
  240. self.translatesAutoresizingMaskIntoConstraints = NO;
  241. ALView *superview = self.superview;
  242. NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
  243. return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)axis ofView:superview];
  244. }
  245. #if __PureLayout_MinBaseSDK_iOS_8_0
  246. /**
  247. Centers the view in its superview, taking into account the layout margins of both the view and its superview.
  248. @return An array of constraints added.
  249. */
  250. - (NSArray *)autoCenterInSuperviewMargins
  251. {
  252. NSMutableArray *constraints = [NSMutableArray new];
  253. [constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisHorizontal]];
  254. [constraints addObject:[self autoAlignAxisToSuperviewMarginAxis:ALAxisVertical]];
  255. return constraints;
  256. }
  257. /**
  258. Aligns the view to the corresponding margin axis of its superview.
  259. @param axis The axis of this view to align to the corresponding margin axis of its superview.
  260. @return The constraint added.
  261. */
  262. - (NSLayoutConstraint *)autoAlignAxisToSuperviewMarginAxis:(ALAxis)axis
  263. {
  264. self.translatesAutoresizingMaskIntoConstraints = NO;
  265. ALView *superview = self.superview;
  266. NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
  267. ALMarginAxis marginAxis = [NSLayoutConstraint al_marginAxisForAxis:axis];
  268. return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)marginAxis ofView:superview];
  269. }
  270. #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */
  271. #pragma mark Pin Edges to Superview
  272. /**
  273. Pins the given edge of the view to the same edge of its superview.
  274. @param edge The edge of this view and its superview to pin.
  275. @return The constraint added.
  276. */
  277. - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge
  278. {
  279. return [self autoPinEdgeToSuperviewEdge:edge withInset:0.0];
  280. }
  281. /**
  282. Pins the given edge of the view to the same edge of its superview with an inset.
  283. @param edge The edge of this view and its superview to pin.
  284. @param inset The amount to inset this view's edge from the superview's edge.
  285. @return The constraint added.
  286. */
  287. - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset
  288. {
  289. return [self autoPinEdgeToSuperviewEdge:edge withInset:inset relation:NSLayoutRelationEqual];
  290. }
  291. /**
  292. Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum.
  293. @param edge The edge of this view and its superview to pin.
  294. @param inset The amount to inset this view's edge from the superview's edge.
  295. @param relation Whether the inset should be at least, at most, or exactly equal to the given value.
  296. @return The constraint added.
  297. */
  298. - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation
  299. {
  300. self.translatesAutoresizingMaskIntoConstraints = NO;
  301. ALView *superview = self.superview;
  302. NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
  303. if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) {
  304. // The bottom, right, and trailing insets (and relations, if an inequality) are inverted to become offsets
  305. inset = -inset;
  306. if (relation == NSLayoutRelationLessThanOrEqual) {
  307. relation = NSLayoutRelationGreaterThanOrEqual;
  308. } else if (relation == NSLayoutRelationGreaterThanOrEqual) {
  309. relation = NSLayoutRelationLessThanOrEqual;
  310. }
  311. }
  312. return [self autoPinEdge:edge toEdge:edge ofView:superview withOffset:inset relation:relation];
  313. }
  314. /**
  315. Pins the edges of the view to the edges of its superview with the given edge insets.
  316. The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
  317. @param insets The insets for this view's edges from its superview's edges.
  318. @return An array of constraints added.
  319. */
  320. - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets
  321. {
  322. NSMutableArray *constraints = [NSMutableArray new];
  323. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
  324. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
  325. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
  326. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
  327. return constraints;
  328. }
  329. /**
  330. Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge.
  331. The insets.left corresponds to a leading edge constraint, and insets.right corresponds to a trailing edge constraint.
  332. @param insets The insets for this view's edges from its superview's edges. The inset corresponding to the excluded edge
  333. will be ignored.
  334. @param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it.
  335. @return An array of constraints added.
  336. */
  337. - (NSArray *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge
  338. {
  339. NSMutableArray *constraints = [NSMutableArray new];
  340. if (edge != ALEdgeTop) {
  341. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:insets.top]];
  342. }
  343. if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
  344. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:insets.left]];
  345. }
  346. if (edge != ALEdgeBottom) {
  347. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:insets.bottom]];
  348. }
  349. if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
  350. [constraints addObject:[self autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:insets.right]];
  351. }
  352. return constraints;
  353. }
  354. #if __PureLayout_MinBaseSDK_iOS_8_0
  355. /**
  356. Pins the given edge of the view to the corresponding margin of its superview.
  357. @param edge The edge of this view to pin to the corresponding margin of its superview.
  358. @return The constraint added.
  359. */
  360. - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge
  361. {
  362. return [self autoPinEdgeToSuperviewMargin:edge relation:NSLayoutRelationEqual];
  363. }
  364. /**
  365. Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum.
  366. @param edge The edge of this view to pin to the corresponding margin of its superview.
  367. @param relation Whether the edge should be inset by at least, at most, or exactly the superview's margin.
  368. @return The constraint added.
  369. */
  370. - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge relation:(NSLayoutRelation)relation
  371. {
  372. self.translatesAutoresizingMaskIntoConstraints = NO;
  373. ALView *superview = self.superview;
  374. NSAssert(superview, @"View's superview must not be nil.\nView: %@", self);
  375. if (edge == ALEdgeBottom || edge == ALEdgeRight || edge == ALEdgeTrailing) {
  376. // The bottom, right, and trailing relations are inverted
  377. if (relation == NSLayoutRelationLessThanOrEqual) {
  378. relation = NSLayoutRelationGreaterThanOrEqual;
  379. } else if (relation == NSLayoutRelationGreaterThanOrEqual) {
  380. relation = NSLayoutRelationLessThanOrEqual;
  381. }
  382. }
  383. ALMargin margin = [NSLayoutConstraint al_marginForEdge:edge];
  384. return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)margin ofView:superview withOffset:0.0 relation:relation];
  385. }
  386. /**
  387. Pins the edges of the view to the margins of its superview.
  388. @return An array of constraints added.
  389. */
  390. - (NSArray *)autoPinEdgesToSuperviewMargins
  391. {
  392. NSMutableArray *constraints = [NSMutableArray new];
  393. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
  394. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
  395. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
  396. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
  397. return constraints;
  398. }
  399. /**
  400. Pins 3 of the 4 edges of the view to the margins of its superview, excluding one edge.
  401. @param edge The edge of this view to exclude in pinning to its superview; this method will not apply any constraint to it.
  402. @return An array of constraints added.
  403. */
  404. - (NSArray *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge
  405. {
  406. NSMutableArray *constraints = [NSMutableArray new];
  407. if (edge != ALEdgeTop) {
  408. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTop]];
  409. }
  410. if (edge != ALEdgeLeading && edge != ALEdgeLeft) {
  411. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeLeading]];
  412. }
  413. if (edge != ALEdgeBottom) {
  414. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeBottom]];
  415. }
  416. if (edge != ALEdgeTrailing && edge != ALEdgeRight) {
  417. [constraints addObject:[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing]];
  418. }
  419. return constraints;
  420. }
  421. #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */
  422. #pragma mark Pin Edges
  423. /**
  424. Pins an edge of the view to a given edge of another view.
  425. @param edge The edge of this view to pin.
  426. @param toEdge The edge of the other view to pin to.
  427. @param otherView The other view to pin to. Must be in the same view hierarchy as this view.
  428. @return The constraint added.
  429. */
  430. - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView
  431. {
  432. return [self autoPinEdge:edge toEdge:toEdge ofView:otherView withOffset:0.0];
  433. }
  434. /**
  435. Pins an edge of the view to a given edge of another view with an offset.
  436. @param edge The edge of this view to pin.
  437. @param toEdge The edge of the other view to pin to.
  438. @param otherView The other view to pin to. Must be in the same view hierarchy as this view.
  439. @param offset The offset between the edge of this view and the edge of the other view.
  440. @return The constraint added.
  441. */
  442. - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset
  443. {
  444. return [self autoPinEdge:edge toEdge:toEdge ofView:otherView withOffset:offset relation:NSLayoutRelationEqual];
  445. }
  446. /**
  447. Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum.
  448. @param edge The edge of this view to pin.
  449. @param toEdge The edge of the other view to pin to.
  450. @param otherView The other view to pin to. Must be in the same view hierarchy as this view.
  451. @param offset The offset between the edge of this view and the edge of the other view.
  452. @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
  453. @return The constraint added.
  454. */
  455. - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
  456. {
  457. return [self autoConstrainAttribute:(ALAttribute)edge toAttribute:(ALAttribute)toEdge ofView:otherView withOffset:offset relation:relation];
  458. }
  459. #pragma mark Align Axes
  460. /**
  461. Aligns an axis of the view to the same axis of another view.
  462. @param axis The axis of this view and the other view to align.
  463. @param otherView The other view to align to. Must be in the same view hierarchy as this view.
  464. @return The constraint added.
  465. */
  466. - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView
  467. {
  468. return [self autoAlignAxis:axis toSameAxisOfView:otherView withOffset:0.0];
  469. }
  470. /**
  471. Aligns an axis of the view to the same axis of another view with an offset.
  472. @param axis The axis of this view and the other view to align.
  473. @param otherView The other view to align to. Must be in the same view hierarchy as this view.
  474. @param offset The offset between the axis of this view and the axis of the other view.
  475. @return The constraint added.
  476. */
  477. - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView withOffset:(CGFloat)offset
  478. {
  479. return [self autoConstrainAttribute:(ALAttribute)axis toAttribute:(ALAttribute)axis ofView:otherView withOffset:offset];
  480. }
  481. #pragma mark Match Dimensions
  482. /**
  483. Matches a dimension of the view to a given dimension of another view.
  484. @param dimension The dimension of this view to pin.
  485. @param toDimension The dimension of the other view to pin to.
  486. @param otherView The other view to match to. Must be in the same view hierarchy as this view.
  487. @return The constraint added.
  488. */
  489. - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView
  490. {
  491. return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withOffset:0.0];
  492. }
  493. /**
  494. Matches a dimension of the view to a given dimension of another view with an offset.
  495. @param dimension The dimension of this view to pin.
  496. @param toDimension The dimension of the other view to pin to.
  497. @param otherView The other view to match to. Must be in the same view hierarchy as this view.
  498. @param offset The offset between the dimension of this view and the dimension of the other view.
  499. @return The constraint added.
  500. */
  501. - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset
  502. {
  503. return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withOffset:offset relation:NSLayoutRelationEqual];
  504. }
  505. /**
  506. Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum.
  507. @param dimension The dimension of this view to pin.
  508. @param toDimension The dimension of the other view to pin to.
  509. @param otherView The other view to match to. Must be in the same view hierarchy as this view.
  510. @param offset The offset between the dimension of this view and the dimension of the other view.
  511. @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
  512. @return The constraint added.
  513. */
  514. - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
  515. {
  516. return [self autoConstrainAttribute:(ALAttribute)dimension toAttribute:(ALAttribute)toDimension ofView:otherView withOffset:offset relation:relation];
  517. }
  518. /**
  519. Matches a dimension of the view to a multiple of a given dimension of another view.
  520. @param dimension The dimension of this view to pin.
  521. @param toDimension The dimension of the other view to pin to.
  522. @param otherView The other view to match to. Must be in the same view hierarchy as this view.
  523. @param multiplier The multiple of the other view's given dimension that this view's given dimension should be.
  524. @return The constraint added.
  525. */
  526. - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier
  527. {
  528. return [self autoMatchDimension:dimension toDimension:toDimension ofView:otherView withMultiplier:multiplier relation:NSLayoutRelationEqual];
  529. }
  530. /**
  531. Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum.
  532. @param dimension The dimension of this view to pin.
  533. @param toDimension The dimension of the other view to pin to.
  534. @param otherView The other view to match to. Must be in the same view hierarchy as this view.
  535. @param multiplier The multiple of the other view's given dimension that this view's given dimension should be.
  536. @param relation Whether the multiple should be at least, at most, or exactly equal to the given value.
  537. @return The constraint added.
  538. */
  539. - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation
  540. {
  541. return [self autoConstrainAttribute:(ALAttribute)dimension toAttribute:(ALAttribute)toDimension ofView:otherView withMultiplier:multiplier relation:relation];
  542. }
  543. #pragma mark Set Dimensions
  544. /**
  545. Sets the view to a specific size.
  546. @param size The size to set this view's dimensions to.
  547. @return An array of constraints added.
  548. */
  549. - (NSArray *)autoSetDimensionsToSize:(CGSize)size
  550. {
  551. NSMutableArray *constraints = [NSMutableArray new];
  552. [constraints addObject:[self autoSetDimension:ALDimensionWidth toSize:size.width]];
  553. [constraints addObject:[self autoSetDimension:ALDimensionHeight toSize:size.height]];
  554. return constraints;
  555. }
  556. /**
  557. Sets the given dimension of the view to a specific size.
  558. @param dimension The dimension of this view to set.
  559. @param size The size to set the given dimension to.
  560. @return The constraint added.
  561. */
  562. - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size
  563. {
  564. return [self autoSetDimension:dimension toSize:size relation:NSLayoutRelationEqual];
  565. }
  566. /**
  567. Sets the given dimension of the view to a specific size as a maximum or minimum.
  568. @param dimension The dimension of this view to set.
  569. @param size The size to set the given dimension to.
  570. @param relation Whether the size should be at least, at most, or exactly equal to the given value.
  571. @return The constraint added.
  572. */
  573. - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation
  574. {
  575. self.translatesAutoresizingMaskIntoConstraints = NO;
  576. NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:(ALAttribute)dimension];
  577. NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:size];
  578. [constraint autoInstall];
  579. return constraint;
  580. }
  581. #pragma mark Set Content Compression Resistance & Hugging
  582. /**
  583. Sets the priority of content compression resistance for an axis.
  584. NOTE: This method must be called from within the block passed into the method +[autoSetPriority:forConstraints:]
  585. @param axis The axis to set the content compression resistance priority for.
  586. */
  587. - (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis
  588. {
  589. NSAssert([ALView al_isExecutingPriorityConstraintsBlock], @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd));
  590. if ([ALView al_isExecutingPriorityConstraintsBlock]) {
  591. self.translatesAutoresizingMaskIntoConstraints = NO;
  592. ALLayoutConstraintAxis constraintAxis = [NSLayoutConstraint al_constraintAxisForAxis:axis];
  593. #if TARGET_OS_IPHONE
  594. [self setContentCompressionResistancePriority:[ALView al_currentGlobalConstraintPriority] forAxis:constraintAxis];
  595. #else
  596. [self setContentCompressionResistancePriority:[ALView al_currentGlobalConstraintPriority] forOrientation:constraintAxis];
  597. #endif /* TARGET_OS_IPHONE */
  598. }
  599. }
  600. /**
  601. Sets the priority of content hugging for an axis.
  602. NOTE: This method must be called from within the block passed into the method +[autoSetPriority:forConstraints:]
  603. @param axis The axis to set the content hugging priority for.
  604. */
  605. - (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis
  606. {
  607. NSAssert([ALView al_isExecutingPriorityConstraintsBlock], @"%@ should only be called from within the block passed into the method +[autoSetPriority:forConstraints:]", NSStringFromSelector(_cmd));
  608. if ([ALView al_isExecutingPriorityConstraintsBlock]) {
  609. self.translatesAutoresizingMaskIntoConstraints = NO;
  610. ALLayoutConstraintAxis constraintAxis = [NSLayoutConstraint al_constraintAxisForAxis:axis];
  611. #if TARGET_OS_IPHONE
  612. [self setContentHuggingPriority:[ALView al_currentGlobalConstraintPriority] forAxis:constraintAxis];
  613. #else
  614. [self setContentHuggingPriority:[ALView al_currentGlobalConstraintPriority] forOrientation:constraintAxis];
  615. #endif /* TARGET_OS_IPHONE */
  616. }
  617. }
  618. #pragma mark Constrain Any Attributes
  619. /**
  620. Constrains an attribute of the view to a given attribute of another view.
  621. This method can be used to constrain different types of attributes across two views.
  622. @param attribute Any attribute of this view to constrain.
  623. @param toAttribute Any attribute of the other view to constrain to.
  624. @param otherView The other view to constrain to. Must be in the same view hierarchy as this view.
  625. @return The constraint added.
  626. */
  627. - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView
  628. {
  629. return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withOffset:0.0];
  630. }
  631. /**
  632. Constrains an attribute of the view to a given attribute of another view with an offset.
  633. This method can be used to constrain different types of attributes across two views.
  634. @param attribute Any attribute of this view to constrain.
  635. @param toAttribute Any attribute of the other view to constrain to.
  636. @param otherView The other view to constrain to. Must be in the same view hierarchy as this view.
  637. @param offset The offset between the attribute of this view and the attribute of the other view.
  638. @return The constraint added.
  639. */
  640. - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset
  641. {
  642. return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withOffset:offset relation:NSLayoutRelationEqual];
  643. }
  644. /**
  645. Constrains an attribute of the view to a given attribute of another view with an offset as a maximum or minimum.
  646. This method can be used to constrain different types of attributes across two views.
  647. @param attribute Any attribute of this view to constrain.
  648. @param toAttribute Any attribute of the other view to constrain to.
  649. @param otherView The other view to constrain to. Must be in the same view hierarchy as this view.
  650. @param offset The offset between the attribute of this view and the attribute of the other view.
  651. @param relation Whether the offset should be at least, at most, or exactly equal to the given value.
  652. @return The constraint added.
  653. */
  654. - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation
  655. {
  656. self.translatesAutoresizingMaskIntoConstraints = NO;
  657. NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:attribute];
  658. NSLayoutAttribute toLayoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:toAttribute];
  659. NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:otherView attribute:toLayoutAttribute multiplier:1.0 constant:offset];
  660. [constraint autoInstall];
  661. return constraint;
  662. }
  663. /**
  664. Constrains an attribute of the view to a given attribute of another view with a multiplier.
  665. This method can be used to constrain different types of attributes across two views.
  666. @param attribute Any attribute of this view to constrain.
  667. @param toAttribute Any attribute of the other view to constrain to.
  668. @param otherView The other view to constrain to. Must be in the same view hierarchy as this view.
  669. @param multiplier The multiplier between the attribute of this view and the attribute of the other view.
  670. @return The constraint added.
  671. */
  672. - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier
  673. {
  674. return [self autoConstrainAttribute:attribute toAttribute:toAttribute ofView:otherView withMultiplier:multiplier relation:NSLayoutRelationEqual];
  675. }
  676. /**
  677. Constrains an attribute of the view to a given attribute of another view with a multiplier as a maximum or minimum.
  678. This method can be used to constrain different types of attributes across two views.
  679. @param attribute Any attribute of this view to constrain.
  680. @param toAttribute Any attribute of the other view to constrain to.
  681. @param otherView The other view to constrain to. Must be in the same view hierarchy as this view.
  682. @param multiplier The multiplier between the attribute of this view and the attribute of the other view.
  683. @param relation Whether the multiplier should be at least, at most, or exactly equal to the given value.
  684. @return The constraint added.
  685. */
  686. - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation
  687. {
  688. self.translatesAutoresizingMaskIntoConstraints = NO;
  689. NSLayoutAttribute layoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:attribute];
  690. NSLayoutAttribute toLayoutAttribute = [NSLayoutConstraint al_layoutAttributeForAttribute:toAttribute];
  691. NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:layoutAttribute relatedBy:relation toItem:otherView attribute:toLayoutAttribute multiplier:multiplier constant:0.0];
  692. [constraint autoInstall];
  693. return constraint;
  694. }
  695. #pragma mark Pin to Layout Guides
  696. #if TARGET_OS_IPHONE
  697. /**
  698. Pins the top edge of the view to the top layout guide of the given view controller with an inset.
  699. For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the top edge of
  700. the view to the top edge of the given view controller's view with an inset.
  701. @param viewController The view controller whose topLayoutGuide should be used to pin to.
  702. @param inset The amount to inset this view's top edge from the layout guide.
  703. @return The constraint added.
  704. */
  705. - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset
  706. {
  707. return [self autoPinToTopLayoutGuideOfViewController:viewController withInset:inset relation:NSLayoutRelationEqual];
  708. }
  709. - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation
  710. {
  711. if (__PureLayout_MinSysVer_iOS_7_0) {
  712. self.translatesAutoresizingMaskIntoConstraints = NO;
  713. NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:relation toItem:viewController.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:inset];
  714. [viewController.view al_addConstraint:constraint]; // Can't use autoInstall because the layout guide is not a view
  715. return constraint;
  716. } else {
  717. // iOS 6 fallback
  718. return [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:viewController.view withOffset:inset relation:relation];
  719. }
  720. }
  721. /**
  722. Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset.
  723. For compatibility with iOS 6 (where layout guides do not exist), this method will simply pin the bottom edge of
  724. the view to the bottom edge of the given view controller's view with an inset.
  725. @param viewController The view controller whose bottomLayoutGuide should be used to pin to.
  726. @param inset The amount to inset this view's bottom edge from the layout guide.
  727. @return The constraint added.
  728. */
  729. - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset
  730. {
  731. return [self autoPinToBottomLayoutGuideOfViewController:viewController withInset:inset relation:NSLayoutRelationEqual];
  732. }
  733. - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation
  734. {
  735. // The bottom inset (and relation, if an inequality) is inverted to become an offset
  736. inset = -inset;
  737. if (relation == NSLayoutRelationLessThanOrEqual) {
  738. relation = NSLayoutRelationGreaterThanOrEqual;
  739. } else if (relation == NSLayoutRelationGreaterThanOrEqual) {
  740. relation = NSLayoutRelationLessThanOrEqual;
  741. }
  742. if (__PureLayout_MinSysVer_iOS_7_0) {
  743. self.translatesAutoresizingMaskIntoConstraints = NO;
  744. NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:relation toItem:viewController.bottomLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:inset];
  745. [viewController.view al_addConstraint:constraint]; // Can't use autoInstall because the layout guide is not a view
  746. return constraint;
  747. } else {
  748. // iOS 6 fallback
  749. return [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:viewController.view withOffset:inset relation:relation];
  750. }
  751. }
  752. #endif /* TARGET_OS_IPHONE */
  753. #pragma mark Deprecated Methods
  754. /**
  755. DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints.
  756. Removes all explicit constraints that affect the view.
  757. WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
  758. It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead.
  759. NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove.
  760. */
  761. - (void)autoRemoveConstraintsAffectingView
  762. {
  763. [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:NO];
  764. }
  765. /**
  766. DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints.
  767. Removes all constraints that affect the view, optionally including implicit constraints.
  768. WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
  769. It is not recommended to use this method to "reset" a view for reuse in a different way with new constraints. Create a new view instead.
  770. NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at
  771. its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these.
  772. @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped.
  773. */
  774. - (void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints
  775. {
  776. NSMutableArray *constraintsToRemove = [NSMutableArray new];
  777. ALView *startView = self;
  778. do {
  779. for (NSLayoutConstraint *constraint in startView.constraints) {
  780. BOOL isImplicitConstraint = [NSStringFromClass([constraint class]) isEqualToString:@"NSContentSizeLayoutConstraint"];
  781. if (shouldRemoveImplicitConstraints || !isImplicitConstraint) {
  782. if (constraint.firstItem == self || constraint.secondItem == self) {
  783. [constraintsToRemove addObject:constraint];
  784. }
  785. }
  786. }
  787. startView = startView.superview;
  788. } while (startView);
  789. [constraintsToRemove autoRemoveConstraints];
  790. }
  791. /**
  792. DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints.
  793. Recursively removes all explicit constraints that affect the view and its subviews.
  794. WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
  795. It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead.
  796. NOTE: This method preserves implicit constraints, such as intrinsic content size constraints, which you usually do not want to remove.
  797. */
  798. - (void)autoRemoveConstraintsAffectingViewAndSubviews
  799. {
  800. [self autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:NO];
  801. }
  802. /**
  803. DEPRECATED as of PureLayout v2.0.0. Retain a reference to and remove specific constraints instead, or recreate the view(s) entirely to remove all constraints.
  804. Recursively removes all constraints that affect the view and its subviews, optionally including implicit constraints.
  805. WARNING: Apple's constraint solver is not optimized for large-scale constraint removal; you may encounter major performance issues after using this method.
  806. It is not recommended to use this method to "reset" views for reuse in a different way with new constraints. Create a new view instead.
  807. NOTE: Implicit constraints are auto-generated lower priority constraints (such as those that attempt to keep a view at
  808. its intrinsic content size by hugging its content & resisting compression), and you usually do not want to remove these.
  809. @param shouldRemoveImplicitConstraints Whether implicit constraints should be removed or skipped.
  810. */
  811. - (void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints
  812. {
  813. [self autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:shouldRemoveImplicitConstraints];
  814. for (ALView *subview in self.subviews) {
  815. [subview autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:shouldRemoveImplicitConstraints];
  816. }
  817. }
  818. #pragma mark Internal Methods
  819. /**
  820. Applies the global constraint priority and identifier to the given constraint.
  821. This should be done before installing all constraints.
  822. @param constraint The constraint to set the global priority and identifier on.
  823. */
  824. + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint
  825. {
  826. if ([ALView al_isExecutingPriorityConstraintsBlock]) {
  827. constraint.priority = [ALView al_currentGlobalConstraintPriority];
  828. }
  829. #if __PureLayout_MinBaseSDK_iOS_8_0
  830. NSString *globalConstraintIdentifier = [ALView al_currentGlobalConstraintIdentifier];
  831. if (globalConstraintIdentifier) {
  832. [constraint autoIdentify:globalConstraintIdentifier];
  833. }
  834. #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */
  835. }
  836. /**
  837. Adds the given constraint to this view after applying the global state to the constraint.
  838. NOTE: This method is compatible with all versions of iOS, and should be used for older versions before the active
  839. property on NSLayoutConstraint was introduced.
  840. This method should be the only one that calls the UIView/NSView addConstraint: method directly.
  841. @param constraint The constraint to set the global priority on and then add to this view.
  842. */
  843. - (void)al_addConstraint:(NSLayoutConstraint *)constraint
  844. {
  845. [ALView al_applyGlobalStateToConstraint:constraint];
  846. if ([ALView al_preventAutomaticConstraintInstallation]) {
  847. [[ALView al_currentArrayOfCreatedConstraints] addObject:constraint];
  848. } else {
  849. [self addConstraint:constraint];
  850. }
  851. }
  852. /**
  853. Returns the common superview for this view and the given other view.
  854. Raises an exception if this view and the other view do not share a common superview.
  855. @return The common superview for the two views.
  856. */
  857. - (ALView *)al_commonSuperviewWithView:(ALView *)otherView
  858. {
  859. ALView *commonSuperview = nil;
  860. ALView *startView = self;
  861. do {
  862. #if TARGET_OS_IPHONE
  863. if ([otherView isDescendantOfView:startView]) {
  864. commonSuperview = startView;
  865. }
  866. #else
  867. if ([otherView isDescendantOf:startView]) {
  868. commonSuperview = startView;
  869. }
  870. #endif /* TARGET_OS_IPHONE */
  871. startView = startView.superview;
  872. } while (startView && !commonSuperview);
  873. NSAssert(commonSuperview, @"Can't constrain two views that do not share a common superview. Make sure that both views have been added into the same view hierarchy.");
  874. return commonSuperview;
  875. }
  876. /**
  877. Aligns this view to another view with an alignment attribute.
  878. @param attribute The attribute to use to align the two views.
  879. @param otherView The other view to align to.
  880. @param axis The axis along which the views are distributed, used to validate the alignment attribute.
  881. @return The constraint added.
  882. */
  883. - (NSLayoutConstraint *)al_alignAttribute:(ALAttribute)attribute toView:(ALView *)otherView forAxis:(ALAxis)axis
  884. {
  885. NSLayoutConstraint *constraint = nil;
  886. switch (attribute) {
  887. case ALAttributeVertical:
  888. NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeVertical.");
  889. constraint = [self autoAlignAxis:ALAxisVertical toSameAxisOfView:otherView];
  890. break;
  891. case ALAttributeHorizontal:
  892. NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeHorizontal.");
  893. constraint = [self autoAlignAxis:ALAxisHorizontal toSameAxisOfView:otherView];
  894. break;
  895. case ALAttributeBaseline: // same value as ALAttributeLastBaseline
  896. NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeBaseline.");
  897. constraint = [self autoAlignAxis:ALAxisBaseline toSameAxisOfView:otherView];
  898. break;
  899. #if __PureLayout_MinBaseSDK_iOS_8_0
  900. case ALAttributeFirstBaseline:
  901. NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALAttributeFirstBaseline is only supported on iOS 8.0 or higher.");
  902. NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeFirstBaseline.");
  903. constraint = [self autoAlignAxis:ALAxisFirstBaseline toSameAxisOfView:otherView];
  904. break;
  905. #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */
  906. case ALAttributeTop:
  907. NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeTop.");
  908. constraint = [self autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:otherView];
  909. break;
  910. case ALAttributeLeft:
  911. NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeLeft.");
  912. constraint = [self autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:otherView];
  913. break;
  914. case ALAttributeBottom:
  915. NSAssert(axis != ALAxisVertical, @"Cannot align views that are distributed vertically with ALAttributeBottom.");
  916. constraint = [self autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:otherView];
  917. break;
  918. case ALAttributeRight:
  919. NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeRight.");
  920. constraint = [self autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:otherView];
  921. break;
  922. case ALAttributeLeading:
  923. NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeLeading.");
  924. constraint = [self autoPinEdge:ALEdgeLeading toEdge:ALEdgeLeading ofView:otherView];
  925. break;
  926. case ALAttributeTrailing:
  927. NSAssert(axis == ALAxisVertical, @"Cannot align views that are distributed horizontally with ALAttributeTrailing.");
  928. constraint = [self autoPinEdge:ALEdgeTrailing toEdge:ALEdgeTrailing ofView:otherView];
  929. break;
  930. default:
  931. NSAssert(nil, @"Unsupported alignment option.");
  932. break;
  933. }
  934. return constraint;
  935. }
  936. @end