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