接上篇繼續進行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
咱們要想讓scrollview
的contentSize
隨內容的變化而變化,那麼就咱們必定要添加註意添加約束:學習
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 }];
對於scrollview
和tableview
,咱們不能使用bottom
來計算其高,由於這個屬性對於scrollview
和tableview
來講,不用用來計算高度的,而是用於計算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);
咱們設置了scrollview
的bottom
爲button
的底部+80
個像素,可是其優先級爲最低。而後又設置了scrollview
的bottom
要大於或者等於self.view
,也就是說contentSize.height
至少爲屏高。
舒適提示:對於UILabel
,若是須要兼容到iOS6.0
,必定要設置preferredMaxLayoutWidth
屬性值,而且其值必定要與約束所生成的寬同樣,不然就會出現顯示不徹底的問題。
Masonry 使用注意:
簡要
自動佈局最重要的是約束:UI元素間關係的數學表達式。約束包括尺寸、由優先級和閾值管理的相對位置。它們是添加劑,可能致使約束衝突 、約束不足形成佈局沒法肯定 。這兩種狀況都會產生異常。
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的大小
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自動佈局詳解二:動畫更新約束
Masonry自動佈局詳解五:比例(multipliedBy)