Masonry 소개 및 사용 실천 (빠 른 시작 Autolayot)

305198 단어 ios
원문:http://adad184.com/2014/09/28/use-masonry-to-quick-solve-autolayout/
Masonry 소개 및 사용 실천 (빠 른 시작 Autolayot)
머리말
        
        
        
        
1
        
        
        
        
MagicNumber -> autoresizingMask -> autolayout

이상 은 순 핸드폰 코드 가 겪 은 페이지 레이아웃 에 관 한 세 시기 입 니 다.
아이 폰 1 - 아이 폰 3gs 시대 window 의 size 는 (320, 480) 로 고정 되 어 있 습 니 다. 우 리 는 상대 적 인 위 치 를 간단하게 계산 하면 됩 니 다 .
아이 폰 4 - 아이 폰 4s 시대 애플 은 리 티 나 스크린 을 내 놓 았 지만 우리 에 게 큰 혜택 을 주 었 다. window 의 size 는 변 하지 않 는 다 .
아이 폰 5 - 아이 폰 5s 시대 에 window 의 size 가 바 뀌 었 다 (320, 568) 이때 autoresizingMask 가 도움 이 되 었 다.
아이 폰 6 + 시대 에 window 의 width 도 변화 가 생 겼 다.
그럼 어떻게 빠르게 autolayot 를 시작 합 니까?솔직히 그 당시 ios 6 출시 와 함께 autolayot 의 특성 이 추가 되 었 습 니 다. 공식 문서 와 demo 를 보고 바로 버 렸 습 니 다. 너무 하 니까 autoresizingMask (경험 이 있 는 친구 들 은 공감 할 것 입 니 다)
아이 폰 6 가 발 표 될 때 까지 나 는 autolayot 를 사용 하 는 것 이 불가피 하 다 는 것 을 알 게 되 었 다. 이때 예전 에 Github 에서 본 제3자 라 이브 러 리 Masonry 가 몇 시간 동안 연 구 를 한 후에 나 는 autolayot 를 파악 했다 autoresizingMask. 이것 이 바로 내 가 왜 이 글 을 써 서 그것 을 추천 해 야 하 는 이유 이다.
소개 하 다.
Masonry 소스 코드
Masonry 는 경량급 의 구조 구조 로 자신의 묘사 문법 을 가지 고 더욱 우아 한 체인 문법 으로 자동 구 조 를 간결 하고 명료 하 며 가 독성 이 높다. 
저희 가 먼저 공식 샘플 코드 를 보고 Masonry 를 만 나 보도 록 하 겠 습 니 다.
        
        
        
        
1
2
3
        
        
        
        
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make .edges .equalTo(superview) .with .insets(padding);
}];

block 안에 있 는 그 말 을 보 았 습 니 다:  autolayout 체인 식 자연 언어 를 통 해 view 1 을 autolayot 에 게 주 는 것 이 쉽 지 않 습 니까?
쓰다
Masonry 가 어떤 속성 을 지원 하 는 지 볼 게 요.
        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
        
        
        
        
@property ( nonatomic, strong, readonly) MASConstraint *left;
@property ( nonatomic, strong, readonly) MASConstraint *top;
@property ( nonatomic, strong, readonly) MASConstraint *right;
@property ( nonatomic, strong, readonly) MASConstraint *bottom;
@property ( nonatomic, strong, readonly) MASConstraint *leading;
@property ( nonatomic, strong, readonly) MASConstraint *trailing;
@property ( nonatomic, strong, readonly) MASConstraint *width;
@property ( nonatomic, strong, readonly) MASConstraint *height;
@property ( nonatomic, strong, readonly) MASConstraint *centerX;
@property ( nonatomic, strong, readonly) MASConstraint *centerY;
@property ( nonatomic, strong, readonly) MASConstraint *baseline;

이 속성 들 은 NSLayoutAttrubute 와 의 대조 표 는 다음 과 같다.
Masonry
NSAutoLayout
설명 하 다.
left
NSLayoutAttributeLeft
좌측
top
NSLayoutAttributeTop
위쪽
right
NSLayoutAttributeRight
오른쪽
bottom
NSLayoutAttributeBottom
아래쪽
leading
NSLayoutAttributeLeading
제1 부
trailing
NSLayoutAttributeTrailing
끝부분
width
NSLayoutAttributeWidth
넓다
height
NSLayoutAttributeHeight
높다
centerX
NSLayoutAttributeCenterX
가로 중심 점
centerY
NSLayoutAttributeCenterY
세로 중심 점
baseline
NSLayoutAttributeBaseline
텍스트 베이스 라인
그 중에서 leading 과 left trailing 과 right 는 정상 적 인 상황 에서 등가 이지 만 일부 구 조 는 오른쪽 에서 왼쪽 일 때 (예 를 들 어 아랍 어? 비슷 한 경험 이 없다) 는 말 을 바 꾸 면 기본적으로 left 와 right 를 사용 하지 않 아 도 된다 는 것 이다.
ios 8 발표 후 또 한 무더기 이상 한 속성 (관심 있 는 친구 보 러 갈 수 있 습 니 다) Masonry 아직 지원 하지 않 습 니 다 (하지만 당신 은 ios 6, ios 7 을 지원 하려 면 그렇게 많은 상관 할 필요 가 없습니다)
실례 를 말씀 드 리 기 전에 먼저 MACRO 를 소개 하 겠 습 니 다.
        
        
        
        
1
        
        
        
        
#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;

weak Self 를 빠르게 정의 하 는 것 은 당연히 block 에 사용 되 는 것 입 니 다. 다음 문제 로 들 어 갑 니 다. (우리 가 테스트 하 는 슈퍼 뷰 는 모두 size (300, 300) 의 UIView 입 니 다.)
다음은 간단 한 실례 를 통 해 어떻게 iOS Max OS X Masonry 를 사용 하 는 지 간단하게 소개 한다.
1. [기초] 가운데 view 보이 기
        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        
        
        
        
- ( void)viewDidLoad
{
[ super viewDidLoad];
// Do any additional setup after loading the view.
WS(ws);
UIView *sv = [ UIView new];
[sv showPlaceHolder];
sv .backgroundColor = [ UIColor blackColor];
[ self .view addSubview:sv];
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
make .center .equalTo(ws .view);
make .size .mas_equalTo(CGSizeMake( 300, 300));
}];
}

코드 효과
내 가 쓴 MMPlace Holder 를 사용 해. 슈퍼 뷰 가 예상 한 대로 가운데 에 있 고 적당 한 크기 로 설정 되 어 있 음 을 볼 수 있 습 니 다.
그럼 이 몇 줄 코드 부터 볼 게 요.
        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        
        
        
        
// CGRectMake
UIView *sv = [ UIView new];
// autoLayout view superview
[ self .view addSubview:sv];
//mas_makeConstraints Masonry autolayout block
[sv mas_makeConstraints:^(MASConstraintMaker *make) {
// sv ( ?)
make .center .equalTo(ws .view);
// size (300,300)
make .size .mas_equalTo(CGSizeMake( 300, 300));
}];

这里有两个问题要分解一下

  • 首先在Masonry中能够添加autolayout约束有三个函数
        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
12
        
        
        
        
- ( NSArray *)mas_makeConstraints:( void(^)(MASConstraintMaker *make))block;
- ( NSArray *)mas_updateConstraints:( void(^)(MASConstraintMaker *make))block;
- ( NSArray *)mas_remakeConstraints:( void(^)(MASConstraintMaker *make))block;
/*
mas_makeConstraints Autolayout
mas_updateConstraints block
mas_remakeConstraints
*/
  • 其次 equalTo 和 mas_equalTo的区别在哪里呢? 其实 mas_equalTo是一个MACRO
        
        
        
        
1
2
3
4
5
        
        
        
        
#define mas_equalTo(...) equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...) greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...) lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_offset(...) valueOffset(MASBoxValue((__VA_ARGS__)))

可以看到 mas_equalTo只是对其参数进行了一个BOX操作(装箱) MASBoxValue的定义具体可以看看源代码 太长就不贴出来了

所支持的类型 除了NSNumber支持的那些数值类型之外 就只支持CGPoint CGSize UIEdgeInsets

介绍完这几个问题 我们就继续往下了 PS:刚才定义的sv会成为我们接下来所有sample的superView

2. [初级] 让一个view略小于其superView(边距为10)

        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        
        
        
        
UIView *sv1 = [ UIView new];
[sv1 showPlaceHolder];
sv1 .backgroundColor = [ UIColor redColor];
[sv addSubview:sv1];
[sv1 mas_makeConstraints:^(MASConstraintMaker *make) {
make .edges .equalTo(sv) .with .insets(UIEdgeInsetsMake( 10, 10, 10, 10));
/*
make.top.equalTo(sv).with.insets(10);
make.left.equalTo(sv).with.insets(10);
make.bottom.equalTo(sv).with.insets(-10);
make.right.equalTo(sv).with.insets(-10);
*/
/*
make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
*/
}];

코드 효과
edges 를 볼 수 있 습 니 다. 사실은 top, left, bottom, right 의 간단 한 구분 으로 써 도 한 마디 가 더 편리 합 니 다.
그럼 왜 bottom 과 right 의 offset 은 마이너스 일 까요?절대 수치 로 계 산 된 bottom 은 작은 물고기 sv 의 밑부분 높이 가 필요 하기 때문에 - 10 동 리 는 right 에 사용 합 니 다.
여기 재 미 있 는 곳 은 make edges equalTo superview with insets 입 니 다. 사실 이 두 함 수 는 아무것도 하지 않 았 어 요.
        
        
        
        
1
2
3
4
5
6
7
        
        
        
        
- (MASConstraint *)with {
return self;
}
- (MASConstraint *)and {
return self;
}

但是用在这种链式语法中 就非常的巧妙和易懂 不得不佩服作者的心思(虽然我现在基本都会省略)

3. [初级] 让两个高度为150的view垂直居中且等宽且等间隔排列 间隔为10(自动计算其宽度)

        
        
        
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        
        
        
        
int padding1 = 10;
[sv2 mas_makeConstraints:^(MASConstraintMaker *make) {
make .centerY .mas_equalTo(sv .mas_centerY);
make .left .equalTo(sv .mas_left) .with .offset(padding1);
make .right .equalTo(sv3 .mas_left) .with .offset(-padding1);
make .height .mas_equalTo(@ 150);
make .width .equalTo(sv3);
}];
[sv3 mas_makeConstraints:^(MASConstraintMaker *make) {
make .centerY .mas_equalTo(sv .mas_centerY);
make .left .equalTo(sv2 .mas_right) .with .offset(padding1);
make .right .equalTo(sv .mas_right) .with .offset(-padding1);
make .height .mas_equalTo(@ 150);
make .width .equalTo(sv2);
}];

代码效果

这里我们在两个子view之间互相设置的约束 可以看到他们的宽度在约束下自动的被计算出来了

4. [中级] 在UIScrollView顺序排列一些view并自动计算contentSize

        
        
        
        
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
        
        
        
        
UIScrollView *scrollView = [ UIScrollView new];
scrollView .backgroundColor = [ UIColor whiteColor];
[sv addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make .edges .equalTo(sv) .with .insets(UIEdgeInsetsMake( 5, 5, 5, 5));
}];
UIView *container = [ UIView new];
[scrollView addSubview:container];
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make .edges .equalTo(scrollView);
make .width .equalTo(scrollView);
}];
int count = 10;
UIView *lastView = nil;
for ( int i = 1 ; i <= count ; ++i )
{
UIView *subv = [ UIView new];
[container addSubview:subv];
subv .backgroundColor = [ UIColor colorWithHue:( arc4random() % 256 / 256.0 )
saturation:( arc4random() % 128 / 256.0 ) + 0.5
brightness:( arc4random() % 128 / 256.0 ) + 0.5
alpha: 1];
[subv mas_makeConstraints:^(MASConstraintMaker *make) {
make .left .and .right .equalTo(container);
make .height .mas_equalTo(@( 20*i));
if ( lastView )
{
make .top .mas_equalTo(lastView .mas_bottom);
}
else
{
make .top .mas_equalTo(container .mas_top);
}
}];
lastView = subv;
}
[container mas_makeConstraints:^(MASConstraintMaker *make) {
make .bottom .equalTo(lastView .mas_bottom);
}];

头部效果
尾部效果

从scrollView的scrollIndicator可以看出 scrollView的内部已如我们所想排列好了

这里的关键就在于container这个view起到了一个中间层的作用 能够自动的计算uiscrollView的contentSize

5. [高级] 横向或者纵向等间隙的排列一组view

很遗憾 autoLayout并没有直接提供等间隙排列的方法(Masonry的官方demo中也没有对应的案例) 但是参考案例3 我们可以通过一个小技巧来实现这个目的 为此我写了一个Category

        
        
        
        
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
        
        
        
        
@implementation UIView(Masonry_LJC)
- ( void) distributeSpacingHorizontallyWith:( NSArray*)views
{
NSMutableArray *spaces = [ NSMutableArray arrayWithCapacity:views .count+ 1];
for ( int i = 0 ; i < views .count+ 1 ; ++i )
{
UIView *v = [ UIView new];
[spaces addObject:v];
[ self addSubview:v];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make .width .equalTo(v .mas_height);
}];
}
for ( int i = 0 ; i < spaces .count ; ++i )
{
UIView *v = spaces[i];
for ( int j = 0 ; j < spaces .count ; ++j )
{
UIView *v2 = spaces[j];
if ( i != j )
{
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make .width .equalTo(v2 .mas_width);
}];
}
}
}
UIView *v0 = spaces[ 0];
__ weak __ typeof(&* self)ws = self;
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make .left .equalTo(ws .mas_left);
make .centerY .equalTo((( UIView*)views[ 0]) .mas_centerY);
}];
UIView *lastSpace = v0;
for ( int i = 0 ; i < views .count; ++i )
{
UIView *obj = views[i];
UIView *space = spaces[i+ 1];
[obj mas_makeConstraints:^(MASConstraintMaker *make) {
make .left .equalTo(lastSpace .mas_right);
}];
[space mas_makeConstraints:^(MASConstraintMaker *make) {
make .left .equalTo(obj .mas_right);
make .centerY .equalTo(obj .mas_centerY);
}];
lastSpace = space;
}
[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make .right .equalTo(ws .mas_right);
}];
}
- ( void) distributeSpacingVerticallyWith:( NSArray*)views
{
NSMutableArray *spaces = [ NSMutableArray arrayWithCapacity:views .count+ 1];
for ( int i = 0 ; i < views .count+ 1 ; ++i )
{
UIView *v = [ UIView new];
[spaces addObject:v];
[ self addSubview:v];
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make .width .equalTo(v .mas_height);
}];
}
for ( int i = 0 ; i < spaces .count ; ++i )
{
UIView *v = spaces[i];
for ( int j = 0 ; j < spaces .count ; ++j )
{
UIView *v2 = spaces[j];
if ( i != j )
{
[v mas_makeConstraints:^(MASConstraintMaker *make) {
make .height .equalTo(v2 .mas_height);
}];
}
}
}
UIView *v0 = spaces[ 0];
__ weak __ typeof(&* self)ws = self;
[v0 mas_makeConstraints:^(MASConstraintMaker *make) {
make .top .equalTo(ws .mas_top);
make .centerX .equalTo((( UIView*)views[ 0]) .mas_centerX);
}];
UIView *lastSpace = v0;
for ( int i = 0 ; i < views .count; ++i )
{
UIView *obj = views[i];
UIView *space = spaces[i+ 1];
[obj mas_makeConstraints:^(MASConstraintMaker *make) {
make .top .equalTo(lastSpace .mas_bottom);
}];
[space mas_makeConstraints:^(MASConstraintMaker *make) {
make .top .equalTo(obj .mas_bottom);
make .centerX .equalTo(obj .mas_centerX);
}];
lastSpace = space;
}
[lastSpace mas_makeConstraints:^(MASConstraintMaker *make) {
make .bottom .equalTo(ws .mas_bottom);
}];
}
@end

简单的来测试一下

        
        
        
        
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
and with
UIView *sv11 = [ UIView new];
UIView *sv12 = [ UIView new];
UIView *sv13 = [ UIView new];
UIView *sv21 = [ UIView new];
UIView *sv31 = [ UIView new];
sv11 .backgroundColor = [ UIColor redColor];
sv12 .backgroundColor = [ UIColor redColor];
sv13 .backgroundColor = [ UIColor redColor];
sv21 .backgroundColor = [ UIColor redColor];
sv31 .backgroundColor = [ UIColor redColor];
[sv addSubview:sv11];
[sv addSubview:sv12];
[sv addSubview:sv13];
[sv addSubview:sv21];
[sv addSubview:sv31];
//
[sv11 mas_makeConstraints:^(MASConstraintMaker *make) {
make .centerY .equalTo(@[sv12,sv13]);
make .centerX .equalTo(@[sv21,sv31]);
make .size .mas_equalTo(CGSizeMake( 40, 40));
}];
[sv12 mas_makeConstraints:^(MASConstraintMaker *make) {
make .size .mas_equalTo(CGSizeMake( 70, 20));
}];
[sv13 mas_makeConstraints:^(MASConstraintMaker *make) {
make .size .mas_equalTo(CGSizeMake( 50, 50));
}];
[sv21 mas_makeConstraints:^(MASConstraintMaker *make) {
make .size .mas_equalTo(CGSizeMake( 50, 20));
}];

코드 효과
perfect! 간결 하고 명료 하 게 우리 가 원 하 는 효 과 를 거 두 었 다.
여기 서 사용 하 는 기술 은 빈 자 리 를 차지 하 는 view 를 사용 하여 목표 view 의 옆 을 채 우 는 것 입 니 다. 이 점 은 그림 의 빈 표 시 를 통 해 알 수 있 습 니 다.
작은 매듭
위의 5 가지 사례 를 통 해 저 는 Masonry 의 상용 기능 을 많이 소개 하지 못 했다 고 생각 합 니 다.
요컨대 Masonry 는 매우 우수한 autolayot 라 이브 러 리 로 서 대량의 개발 과 학습 시간 을 절약 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기