Coding源碼學習第四部分(Masonry介紹與使用(三))

接上篇繼續進行Masonry 的學習。html

 (12)tableViewCell 佈局ios

 1 #import "TableViewController.h"
 2 #import "TestTableViewCell.h"
 3 
 4 @interface TableViewController ()<UITableViewDelegate, UITableViewDataSource>
 5 
 6 @property(nonatomic, strong) UITableView *tableView;
 7 @property(nonatomic, strong) NSMutableArray *dataSource;
 8 
 9 @end
10 
11 @implementation TableViewController
12 
13 - (void)viewDidLoad {
14     [super viewDidLoad];
15     // Do any additional setup after loading the view.
16     
17     self.tableView = [[UITableView alloc] init];
18     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
19     self.tableView.delegate = self;
20     self.tableView.dataSource = self;
21     [self.view addSubview:self.tableView];
22     [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
23         make.edges.mas_equalTo(self.view);
24     }];
25     
26     for (NSUInteger i = 0; i < 10; ++i) {
27         TestModel *model = [[TestModel alloc] init];
28         model.title = @"測試標題, 可能很長很長,反正隨便寫着先吧";
29         model.desc = @"描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,描述內容一般都是很長很長的,";
30         [self.dataSource addObject:model];
31     }
32     [self.tableView reloadData];
33 }
34 
35 - (NSMutableArray *)dataSource {
36     if (_dataSource == nil) {
37         _dataSource = [[NSMutableArray alloc] init];
38     }
39     return _dataSource;
40 }
41 
42 #pragma mark - UITableViewDataSource
43 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
44     return self.dataSource.count;
45 }
46 
47 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
48     static NSString *cellIdentifier = @"CellIdentifier";
49     TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
50     if (!cell) {
51         cell = [[TestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
52     }
53     cell.indexPath = indexPath;
54     cell.block = ^(NSIndexPath *path) {
55         [tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationFade];
56     };
57     TestModel *model = [self.dataSource objectAtIndex:indexPath.row];
58     [cell configCellWithModel:model];
59     return cell;
60 }
61 
62 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
63     TestModel *model = [self.dataSource objectAtIndex:indexPath.row];
64     return [TestTableViewCell heightWithModel:model];
65 }
66 - (void)didReceiveMemoryWarning {
67     [super didReceiveMemoryWarning];
68     // Dispose of any resources that can be recreated.
69 }
70 
71 /*
72 #pragma mark - Navigation
73 
74 // In a storyboard-based application, you will often want to do a little preparation before navigation
75 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
76     // Get the new view controller using [segue destinationViewController].
77     // Pass the selected object to the new view controller.
78 }
79 */
80 
81 @end

 

咱們來看看這個計算行高的代碼,看起來是否是很像配置數據的代理方法呢?app

1 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
2     TestModel *model = [self.dataSource objectAtIndex:indexPath.row];
3     return [TestTableViewCell heightWithModel:model];
4 }

咱們看看TestCell的聲明,提供了一個計算行高的類方法:less

 1 #import <UIKit/UIKit.h>
 2 
 3 @interface TestModel : NSObject
 4 
 5 @property(nonatomic, copy) NSString *title;
 6 @property(nonatomic, copy) NSString *desc;
 7 @property(nonatomic, assign) BOOL isExpanded;
 8 
 9 @end
10 
11 typedef void (^TestBlock)(NSIndexPath *indexPath);
12 
13 @interface TestTableViewCell : UITableViewCell
14 
15 @property(nonatomic, strong) UILabel *titleLabel;
16 @property(nonatomic, strong) UILabel *descLabel;
17 @property(nonatomic, strong) NSIndexPath *indexPath;
18 
19 @property(nonatomic, copy) TestBlock block;
20 
21 - (void)configCellWithModel:(TestModel *)model;
22 + (CGFloat)heightWithModel:(TestModel *)model;
23 
24 @end

咱們看一下計算行高的實現:dom

1 + (CGFloat)heightWithModel:(TestModel *)model {
2     TestTableViewCell *cell = [[TestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@""];
3     [cell configCellWithModel:model];
4     [cell layoutIfNeeded];
5     CGRect frame = cell.descLabel.frame;
6     return frame.origin.y + frame.size.height + 20;
7 }

咱們只是建立了一個cell而後配置數據,而後調用layoutIfNeeded更新約束,以便獲取到frame。當咱們獲取到之後,咱們就能夠計算出最後的cell真正的高度了。ide

(13)ScrollView循環佈局佈局

 1 #import "ScrollViewController.h"
 2 
 3 @interface ScrollViewController ()
 4 
 5 @property (nonatomic, strong) UIScrollView *scrollView;
 6 
 7 @end
 8 
 9 @implementation ScrollViewController
10 
11 - (void)viewDidLoad {
12   [super viewDidLoad];
13   
14   self.scrollView = [[UIScrollView alloc] init];
15   self.scrollView.pagingEnabled = NO;
16   [self.view addSubview:self.scrollView];
17   self.scrollView.backgroundColor = [UIColor lightGrayColor];
18 
19   CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
20   UILabel *lastLabel = nil;
21   for (NSUInteger i = 0; i < 20; ++i) {
22     UILabel *label = [[UILabel alloc] init];
23     label.numberOfLines = 0;
24     label.layer.borderColor = [UIColor greenColor].CGColor;
25     label.layer.borderWidth = 2.0;
26     label.text = [self randomText];
27     
28     // We must preferredMaxLayoutWidth property for adapting to iOS6.0
29     label.preferredMaxLayoutWidth = screenWidth - 30;
30     label.textAlignment = NSTextAlignmentLeft;
31     label.textColor = [self randomColor];
32     [self.scrollView addSubview:label];
33     
34     [label mas_makeConstraints:^(MASConstraintMaker *make) {
35       make.left.mas_equalTo(15);
36       make.right.mas_equalTo(self.view).offset(-15);
37       
38       if (lastLabel) {
39         make.top.mas_equalTo(lastLabel.mas_bottom).offset(20);
40       } else {
41         make.top.mas_equalTo(self.scrollView).offset(20);
42       }
43     }];
44     
45     lastLabel = label;
46   }
47   
48   [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
49     make.edges.mas_equalTo(self.view);
50 
51     // 讓scrollview的contentSize隨着內容的增多而變化
52     make.bottom.mas_equalTo(lastLabel.mas_bottom).offset(20);
53   }];
54 }
55 
56 - (UIColor *)randomColor {
57   CGFloat hue = ( arc4random() % 256 / 256.0 );  //  0.0 to 1.0
58   CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from white
59   CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from black
60   return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
61 }
62 
63 - (NSString *)randomText {
64   CGFloat length = arc4random() % 50 + 5;
65   
66   NSMutableString *str = [[NSMutableString alloc] init];
67   for (NSUInteger i = 0; i < length; ++i) {
68     [str appendString:@"測試數據很長,"];
69   }
70   
71   return str;
72 }
73 
74 @end

對於循環建立,咱們須要記錄下一個視圖所依賴的控件,這裏使用了lastLabel來記錄。post

咱們要想讓scrollviewcontentSize隨內容的變化而變化,那麼就咱們必定要添加註意添加約束:學習

1     
2     [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
3         make.edges.mas_equalTo(self.view);
4         
5         // 讓scrollView 的contentSize 隨着內容的增多而變化
6         make.bottom.mas_equalTo(lastLabel.mas_bottom).offset(20);
7     }];

對於scrollviewtableview,咱們不能使用bottom來計算其高,由於這個屬性對於scrollviewtableview來講,不用用來計算高度的,而是用於計算contentSize.height的。咱們要想隨內容而變化,以即可滾動查看,就必須設置bottom約束。測試

 (14)複雜ScrollerView 佈局

  1 #import "ScrollViewComplexController.h"
  2 
  3 @interface ScrollViewComplexController ()
  4 
  5 @property (nonatomic, strong) UIScrollView *scrollView;
  6 @property (nonatomic, strong) NSMutableArray *expandStates;
  7 
  8 @end
  9 
 10 @implementation ScrollViewComplexController
 11 
 12 - (void)viewDidLoad {
 13   [super viewDidLoad];
 14  
 15   self.scrollView = [[UIScrollView alloc] init];
 16   self.scrollView.pagingEnabled = NO;
 17   [self.view addSubview:self.scrollView];
 18   self.scrollView.backgroundColor = [UIColor lightGrayColor];
 19   
 20   CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
 21   UILabel *lastLabel = nil;
 22   for (NSUInteger i = 0; i < 10; ++i) {
 23     UILabel *label = [[UILabel alloc] init];
 24     label.numberOfLines = 0;
 25     label.layer.borderColor = [UIColor greenColor].CGColor;
 26     label.layer.borderWidth = 2.0;
 27     label.text = [self randomText];
 28     label.userInteractionEnabled = YES;
 29     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
 30     [label addGestureRecognizer:tap];
 31     
 32     // We must preferredMaxLayoutWidth property for adapting to iOS6.0
 33     label.preferredMaxLayoutWidth = screenWidth - 30; // iOS 6 的用法
 34     label.textAlignment = NSTextAlignmentLeft;
 35     label.textColor = [self randomColor];
 36     [self.scrollView addSubview:label];
 37     
 38     [label mas_makeConstraints:^(MASConstraintMaker *make) {
 39       make.left.mas_equalTo(15);
 40       make.right.mas_equalTo(self.view).offset(-15);
 41       
 42       if (lastLabel) {
 43         make.top.mas_equalTo(lastLabel.mas_bottom).offset(20);
 44       } else {
 45         make.top.mas_equalTo(self.scrollView).offset(20);
 46       }
 47       
 48       make.height.mas_equalTo(40);
 49     }];
 50     
 51     lastLabel = label;
 52     
 53     [self.expandStates addObject:[@[label, @(NO)] mutableCopy]];
 54   }
 55   
 56   [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
 57     make.edges.mas_equalTo(self.view);
 58     
 59     // 讓scrollview的contentSize隨着內容的增多而變化
 60     make.bottom.mas_equalTo(lastLabel.mas_bottom).offset(20);
 61   }];
 62 }
 63 
 64 - (NSMutableArray *)expandStates {
 65   if (_expandStates == nil) {
 66     _expandStates = [[NSMutableArray alloc] init];
 67   }
 68   
 69   return _expandStates;
 70 }
 71 
 72 - (UIColor *)randomColor {
 73   CGFloat hue = ( arc4random() % 256 / 256.0 );  //  0.0 to 1.0
 74   CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from white
 75   CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from black
 76   return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];
 77 }
 78 
 79 - (NSString *)randomText {
 80   CGFloat length = arc4random() % 150 + 5;
 81   
 82   NSMutableString *str = [[NSMutableString alloc] init];
 83   for (NSUInteger i = 0; i < length; ++i) {
 84     [str appendString:@"測試數據很長,"];
 85   }
 86   
 87   return str;
 88 }
 89 
 90 - (void)onTap:(UITapGestureRecognizer *)sender {
 91   UIView *tapView = sender.view;
 92   
 93   NSUInteger index = 0;
 94   for (NSMutableArray *array in self.expandStates) {
 95     UILabel *view = [array firstObject];
 96     
 97     if (view == tapView) {
 98       NSNumber *state = [array lastObject];
 99       
100       // 當前是展開狀態的話,就收縮
101       if ([state boolValue] == YES) {
102         [view mas_updateConstraints:^(MASConstraintMaker *make) {
103           make.height.mas_equalTo(40);
104         }];
105       } else {
106         UIView *preView = nil;
107         UIView *nextView = nil;
108         
109         if (index - 1 < self.expandStates.count && index >= 1) {
110           preView = [[self.expandStates objectAtIndex:index - 1] firstObject];
111         }
112         
113         if (index + 1 < self.expandStates.count) {
114            nextView = [[self.expandStates objectAtIndex:index + 1] firstObject];
115         }
116 
117         [view mas_remakeConstraints:^(MASConstraintMaker *make) {
118           if (preView) {
119             make.top.mas_equalTo(preView.mas_bottom).offset(20);
120           } else {
121             make.top.mas_equalTo(20);
122           }
123           
124           make.left.mas_equalTo(15);
125           make.right.mas_equalTo(self.view).offset(-15);
126         }];
127         
128         if (nextView) {
129           [nextView mas_updateConstraints:^(MASConstraintMaker *make) {
130             make.top.mas_equalTo(view.mas_bottom).offset(20);
131           }];
132         }
133       }
134       
135       [array replaceObjectAtIndex:1 withObject:@(!state.boolValue)];
136       
137       [self.view setNeedsUpdateConstraints];
138       [self.view updateConstraintsIfNeeded];
139 
140       [UIView animateWithDuration:0.35 animations:^{
141         [self.view layoutIfNeeded];
142       } completion:^(BOOL finished) {
143 
144       }];
145       break;
146     }
147     
148     index++;
149   }
150 }
151 
152 @end

當咱們要收起的時候,只是簡單地設置其高度的約束爲40,可是當咱們要展開時,實現起來就相對麻煩了。由於咱們須要從新添加約束,要從新給所點擊的視圖添加約束,就須要知道前一個依賴視圖和後一個依賴視圖的約束,以便將相關聯的都更新約束。

當咱們更新所點擊的視圖時,咱們經過判斷是否有前一個依賴視圖來設置頂部約束:

1                     if (preView) {
2                         make.top.mas_equalTo(preView.mas_bottom).offset(20);
3                     } else {
4                         make.top.mas_equalTo(20);
5                     }

除了這個以外,咱們也須要更新後一個視圖的約束,由於咱們對所點擊的視圖調用了mas_remakeConstraints方法,就會移除其以前所添加的全部約束,因此咱們必須從新將後者對當前點擊的視圖的依賴從新添加上去:

1                 if (nextView) {
2                     [nextView mas_updateConstraints:^(MASConstraintMaker *make) {
3                         make.top.mas_equalTo(view.mas_bottom).offset(20);
4                     }];
5                 }

(15)scrollView 實戰場景

  1 #import "HeaderFooterViewController.h"
  2 
  3 @interface HeaderFooterViewController ()
  4 
  5 @property(nonatomic, strong) UIScrollView *scrollView;
  6 @property(nonatomic, strong) UITableView *tableView;
  7 
  8 @end
  9 
 10 @implementation HeaderFooterViewController
 11 
 12 - (void)viewDidLoad {
 13     [super viewDidLoad];
 14     // Do any additional setup after loading the view.
 15     [self configTableView];
 16 }
 17 
 18 - (void)configScrollView {
 19     self.scrollView = [[UIScrollView alloc] init];
 20     [self.view addSubview:self.scrollView];
 21     [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
 22         make.edges.mas_equalTo(self.view);
 23     }];
 24     
 25     UIView *headerView = [[UIView alloc] init];
 26     [self.scrollView addSubview:headerView];
 27     
 28     UIImageView *imgView = [[UIImageView alloc] init];
 29     [headerView addSubview:imgView];
 30     imgView.backgroundColor = [UIColor greenColor];
 31     imgView.layer.cornerRadius = 50;
 32     imgView.layer.masksToBounds = YES;
 33     imgView.layer.borderWidth = 0.5;
 34     imgView.layer.borderColor = [UIColor redColor].CGColor;
 35     
 36     CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
 37     
 38     UILabel *tipLabel = [[UILabel alloc] init];
 39     tipLabel.text = @"這裏是提示信息,一般會比較長,可能會超過兩行。爲了適配6.0,咱們須要指定preferredMaxLayoutWidth,可是要注意,此屬性一旦設置,不是隻在6.0上生效,任意版本的系統的都有做用,所以此值設置得必定要準備,不然計算結果會不正確。咱們必定要注意,不能給tableview的tableHeaderView和tableFooterView添加約束,在6.0及其如下版本上會crash,其它版本沒有";
 40     tipLabel.textAlignment = NSTextAlignmentCenter;
 41     tipLabel.textColor = [UIColor blackColor];
 42     tipLabel.backgroundColor = [UIColor clearColor];
 43     tipLabel.numberOfLines = 0;
 44     tipLabel.preferredMaxLayoutWidth = screenWidth - 30;
 45     [headerView addSubview:tipLabel];
 46     
 47     UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
 48     [button setTitle:@"show Detail" forState:UIControlStateNormal];
 49     [button setTitleColor: [UIColor whiteColor] forState:UIControlStateNormal];
 50     [button setBackgroundColor:[UIColor blueColor]];
 51     button.layer.cornerRadius = 6;
 52     button.clipsToBounds = YES;
 53     button.layer.masksToBounds = YES;
 54     
 55     [headerView  addSubview:button];
 56     
 57     [headerView mas_makeConstraints:^(MASConstraintMaker *make) {
 58         make.left.top.mas_equalTo(0);
 59         make.width.mas_equalTo(self.view);
 60         make.bottom.mas_equalTo(button.mas_bottom).offset(60).priorityLow();
 61         make.height.greaterThanOrEqualTo(self.view);
 62     }];
 63     
 64     [imgView mas_makeConstraints:^(MASConstraintMaker *make) {
 65         make.top.mas_equalTo(80);
 66         make.centerX.mas_equalTo(headerView);
 67         make.width.height.mas_equalTo(100);
 68     }];
 69     
 70     [tipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
 71         make.left.mas_equalTo(15);
 72         make.right.mas_equalTo(-15);
 73         make.top.mas_equalTo(imgView.mas_bottom).offset(40);
 74     }];
 75     
 76     [button mas_makeConstraints:^(MASConstraintMaker *make) {
 77         make.top.mas_greaterThanOrEqualTo(tipLabel.mas_bottom).offset(80);
 78         make.left.mas_equalTo(15);
 79         make.right.mas_equalTo(-15);
 80         make.height.mas_equalTo(45);
 81     }];
 82     
 83     [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
 84         make.bottom.mas_equalTo(button.mas_bottom).offset(80).priorityLow();
 85         make.bottom.mas_greaterThanOrEqualTo(self.view);
 86     }];
 87 }
 88 
 89 - (void)configTableView {
 90     if (self.tableView != nil) {
 91         return;
 92     }
 93     self.tableView = [[UITableView alloc] init];
 94     [self.view addSubview:self.tableView];
 95     [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
 96         make.edges.mas_equalTo(self.view);
 97     }];
 98     
 99     NSArray *array = [self headerViewWithHeight:self.view.frame.size.height addToView:self.view];
100     UIView *headerView = [array firstObject];
101     [headerView layoutIfNeeded];
102     UIButton *button = [array lastObject];
103     CGFloat h = button.frame.size.height + button.frame.origin.y + 40;
104     h = h < self.view.frame.size.height ? self.view.frame.size.height : h;
105     
106     [headerView removeFromSuperview];
107     [self headerViewWithHeight:h addToView:nil];
108 }
109 
110 - (NSArray *)headerViewWithHeight:(CGFloat)height addToView:(UIView *)toView {
111     // 注意, 絕對不能給tableHeaderView 直接添加約束, 必閃退
112     UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, height)];
113     
114     if (toView) {
115         [toView addSubview:headerView];
116     } else {
117         self.tableView.tableHeaderView = headerView;
118     }
119     
120     UIImageView *imgView = [[UIImageView alloc] init];
121     [headerView addSubview:imgView];
122     imgView.backgroundColor = [UIColor greenColor];
123     imgView.layer.cornerRadius = 50;
124     imgView.layer.masksToBounds = YES;
125     imgView.layer.borderWidth = 0.5;
126     imgView.layer.borderColor = [UIColor redColor].CGColor;
127     
128     CGFloat screentWidth = [UIScreen mainScreen].bounds.size.width;
129     
130     UILabel *tipLabel = [[UILabel alloc] init];
131     tipLabel.text = @"這裏是提示信息,一般會比較長,可能會超過兩行。爲了適配6.0,咱們須要指定preferredMaxLayoutWidth,可是要注意,此屬性一旦設置,不是隻在6.0上生效,任意版本的系統的都有做用,所以此值設置得必定要準備,不然計算結果會不正確。咱們必定要注意,不能給tableview的tableHeaderView和tableFooterView添加約束,在6.0及其如下版本上會crash,其它版本沒有";
132     tipLabel.textAlignment = NSTextAlignmentCenter;
133     tipLabel.textColor = [UIColor blackColor];
134     tipLabel.backgroundColor = [UIColor clearColor];
135     tipLabel.numberOfLines = 0;
136     tipLabel.preferredMaxLayoutWidth = screentWidth - 30;
137     [headerView addSubview:tipLabel];
138     
139     UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
140     [button setTitle:@"Show detail" forState:UIControlStateNormal];
141     [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
142     [button setBackgroundColor:[UIColor blueColor]];
143     button.layer.cornerRadius = 6;
144     button.clipsToBounds = YES;
145     button.layer.masksToBounds = YES;
146     
147     [headerView addSubview:button];
148     
149     [imgView mas_makeConstraints:^(MASConstraintMaker *make) {
150         make.top.mas_equalTo(80);
151         make.centerX.mas_equalTo(headerView);
152         make.width.height.mas_equalTo(100);
153     }];
154     
155     [tipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
156         make.left.mas_equalTo(self.view).offset(15);
157         make.right.mas_equalTo(self.view).offset(-15);
158         make.top.mas_equalTo(imgView.mas_bottom).offset(40);
159     }];
160     
161     [button mas_makeConstraints:^(MASConstraintMaker *make) {
162         make.top.mas_greaterThanOrEqualTo(tipLabel.mas_bottom).offset(80);
163         make.left.mas_equalTo(tipLabel);
164         make.right.mas_equalTo(tipLabel);
165         make.height.mas_equalTo(45);
166     }];
167     
168     return @[headerView, button];
169 }
170 - (void)didReceiveMemoryWarning {
171     [super didReceiveMemoryWarning];
172     // Dispose of any resources that can be recreated.
173 }
174 
175 /*
176 #pragma mark - Navigation
177 
178 // In a storyboard-based application, you will often want to do a little preparation before navigation
179 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
180     // Get the new view controller using [segue destinationViewController].
181     // Pass the selected object to the new view controller.
182 }
183 */
184 
185 @end

 這裏只是說說如何設置約束以保證按鈕的位置始終是有必定距離的:

 1 make.bottom.mas_equalTo(button.mas_bottom).offset(80).priorityLow(); 2 3 4 5 make.bottom.mas_greaterThanOrEqualTo(self.view); 

咱們設置了scrollviewbottombutton的底部+80個像素,可是其優先級爲最低。而後又設置了scrollviewbottom要大於或者等於self.view,也就是說contentSize.height至少爲屏高。

舒適提示:對於UILabel,若是須要兼容到iOS6.0,必定要設置preferredMaxLayoutWidth屬性值,而且其值必定要與約束所生成的寬同樣,不然就會出現顯示不徹底的問題。

Masonry 使用注意:

簡要

自動佈局最重要的是約束:UI元素間關係的數學表達式。約束包括尺寸、由優先級和閾值管理的相對位置。它們是添加劑,可能致使約束衝突 、約束不足形成佈局沒法肯定 。這兩種狀況都會產生異常。

使用前:AutoLayout關於更新的幾個方法的區別

  • setNeedsLayout:告知頁面須要更新,可是不會馬上開始更新。執行後會馬上調用layoutSubviews。
  • layoutIfNeeded:告知頁面佈局馬上更新。因此通常都會和setNeedsLayout一塊兒使用。若是但願馬上生成新的frame須要調用此方法,利用這點通常佈局動畫能夠在更新佈局後直接使用這個方法讓動畫生效。
  • layoutSubviews:系統重寫佈局
  • setNeedsUpdateConstraints:告知須要更新約束,可是不會馬上開始
  • updateConstraintsIfNeeded:告知馬上更新約束
  • updateConstraints:系統更新約束

前面沒有提到的使用細節:

  • multipler屬性表示約束值爲約束對象的乘因數, dividedBy屬性表示約束值爲約束對象的除因數,可用於設置view的寬高比
  • priorityLow()設置約束優先級
  • #define MAS_SHORTHAND_GLOBALS使用全局宏定義,可使equalTo等效於mas_equalTo
  • #define MAS_SHORTHAND使用全局宏定義, 能夠在調用masonry方法的時候不使用mas_前綴
1 // 這裏注意到一個地方,就是當使用了這個全局宏定義以後,發現能夠有個類`NSArray+MASAdditions.h`,看了以後發現能夠
2 self.buttonViews = @[ raiseButton, lowerButton, centerButton ];
3 // 以後能夠在updateConstraints 方法中
4 - (void)updateConstraints {
5    [self.buttonViews updateConstraints:^(MASConstraintMaker *make) {
6         make.baseline.equalTo(self.mas_centerY).with.offset(self.offset);
7     }];
8     [super updateConstraints];  
9 }
  • 動態修改視圖約束:
1 // 建立視圖約束
2 [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
3       self.animatableConstraint = make.edges.equalTo(superview).insets(paddingInsets).priorityLow();
4 ]];
5 // 更改約束 (另外一處方法中)
6 UIEdgeInsets paddingInsets = UIEdgeInsetsMake(padding, padding, padding, padding);
7 self.animatableConstraint.insets = paddingInsets;
8 [self layoutIfNeeded];
  • debug模式:
1 // 對某個view添加key值
2 greenView.mas_key = @"greenView";
3 // 或者以下順序
4 MASAttachKeys(greenView, redView, blueView, superview);
5 // 一樣的對每條約束亦能夠添加key
6 make.height.greaterThanOrEqualTo(@5000).key(@"ConstantConstraint");
  • preferredMaxLayoutWidth: 多行label的約束問題 iOS 6。
1 // 已經確認好了位置
2 // 在layoutSubviews中確認label的preferredMaxLayoutWidth值
3 - (void)layoutSubviews {
4     [super layoutSubviews];
5     // 你必須在 [super layoutSubviews] 調用以後,longLabel的frame有值以後設置preferredMaxLayoutWidth
6     self.longLabel.preferredMaxLayoutWidth = self.frame.size.width-100;
7     // 設置preferredLayoutWidth後,須要從新佈局
8     [super layoutSubviews];
9 }
  • scrollView使用約束的問題:原理經過一個contentView來約束scrollView的contentSize大小,也就是說以子控件的約束條件,來控制父視圖的大小。
 1 // 1. 控制scrollView大小(顯示區域)
 2 [self.scrollView makeConstraints:^(MASConstraintMaker *make) {
 3      make.edges.equalTo(self.view);
 4 }];
 5 // 2. 添加一個contentView到scrollView,而且添加好約束條件
 6 [contentView makeConstraints:^(MASConstraintMaker *make) {
 7      make.edges.equalTo(self.scrollView);
 8      // 注意到此處的寬度約束條件,這個寬度的約束條件是必添加項
 9      make.width.equalTo(self.scrollView);
10 }];
11 // 3. 對contentView的子控件作好約束,達到能夠控制contentView的大小
  • 新方法:2個或2個以上的控件等間隔排序。
 1 /**
 2  *  多個控件固定間隔的等間隔排列,變化的是控件的長度或者寬度值
 3  *
 4  *  @param axisType        軸線方向
 5  *  @param fixedSpacing    間隔大小
 6  *  @param leadSpacing     頭部間隔
 7  *  @param tailSpacing     尾部間隔
 8  */
 9 - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType 
10                     withFixedSpacing:(CGFloat)fixedSpacing l
11                           eadSpacing:(CGFloat)leadSpacing 
12                          tailSpacing:(CGFloat)tailSpacing;
13 
14 /**
15  *  多個固定大小的控件的等間隔排列,變化的是間隔的空隙
16  *
17  *  @param axisType        軸線方向
18  *  @param fixedItemLength 每一個控件的固定長度或者寬度值
19  *  @param leadSpacing     頭部間隔
20  *  @param tailSpacing     尾部間隔
21  */
22 - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType 
23                  withFixedItemLength:(CGFloat)fixedItemLength 
24                          leadSpacing:(CGFloat)leadSpacing 
25                          tailSpacing:(CGFloat)tailSpacing;
1 //  使用方法很簡單,由於它是NSArray的類擴展:
2 
3 //  建立水平排列圖標 arr中放置了2個或連個以上的初始化後的控件
4 //  alongAxis 軸線方向   固定間隔     頭部間隔      尾部間隔
5 [arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
6 [arr makeConstraints:^(MASConstraintMaker *make) {
7        make.top.equalTo(@60);
8        make.height.equalTo(@60);
9 }];
  • 約束視圖對象只有在被addSubview以後,才能給視圖添加約束。
  • 當你的全部約束都在 updateConstraints 內調用的時候,你就須要在此調用此方法,由於 updateConstraints方法是須要觸發的。
 1 // 調用在view 內部,而不是viewcontroller
 2 + (BOOL)requiresConstraintBasedLayout {
 3     return YES;
 4 }
 5 
 6 /**
 7  *  蘋果推薦 約束 增長和修改 放在此方法種
 8  */
 9 - (void)updateConstraints {
10     [self.growingButton updateConstraints:^(MASConstraintMaker *make) {
11         make.center.equalTo(self);
12         make.width.equalTo(@(self.buttonSize.width)).priorityLow();
13         make.height.equalTo(@(self.buttonSize.height)).priorityLow();
14         make.width.lessThanOrEqualTo(self);
15         make.height.lessThanOrEqualTo(self);
16     }];
17     //最後記得回調super方法
18     [super updateConstraints];
19 }
  • 若是想要約束變換以後實現動畫效果,則須要執行以下操做
1 // 通知須要更新約束,可是不當即執行
2 [self setNeedsUpdateConstraints];
3 // 當即更新約束,以執行動態變換
4 // update constraints now so we can animate the change
5 [self updateConstraintsIfNeeded];
6 // 執行動畫效果, 設置動畫時間
7 [UIView animateWithDuration:0.4 animations:^{
8    [self layoutIfNeeded];
9 }];

 

 

參考連接:

Masonry介紹與使用實踐(快速上手Autolayout)  

Masonry使用心得  

Masonry的簡單使用  

IOS自適應前段庫-Masonry的使用 

iOS_autoLayout_Masonry  

Masonry自動佈局詳解一:基本用法Masonry自動佈局詳解二:動畫更新約束  

Masonry自動佈局詳解三:remake約束 

Masonry自動佈局詳解四:總體動畫更新約束  

Masonry自動佈局詳解五:比例(multipliedBy)  

Masonry自動佈局詳解六:tableviewCell佈局  

Masonry自動佈局詳解七:ScrollView循環佈局  

Masonry自動佈局詳解八:複雜ScrollView佈局  

Masonry自動佈局詳解九:scrollview實戰場  

Masonry使用注意篇 

相關文章
相關標籤/搜索