一. 使用baseline
1 2 3 4 5 6 7
| #pragma mark - Override
- (UIView *)viewForBaselineLayout { return _baseView; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| [item1 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.view.mas_left).with.offset(8); make.top.mas_equalTo(self.view.mas_top).with.offset(200); }];
[item2 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(item1.mas_right).with.offset(10); make.baseline.mas_equalTo(item1.mas_baseline); }];
[item3 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(item2.mas_right).with.offset(10); make.baseline.mas_equalTo(item1.mas_baseline); }];
|
二. 在屏幕边缘控件布局技巧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| - (void)updateViewConstraints { #ifndef NEW_FEATURE // 根据新的length值更新约束 [_topView mas_updateConstraints:^(MASConstraintMaker *make) { // 直接利用其length属性,避免iOS、SDK版本升级后topLayoutGuide不再是UIView make.top.equalTo(self.view.mas_top).with.offset(self.topLayoutGuide.length); NSLog(@"[updateViewConstraints] top: %g", self.topLayoutGuide.length); }]; // 根据新的length值更新约束 [_bottomView mas_updateConstraints:^(MASConstraintMaker *make) { // 直接利用其length属性,避免iOS、SDK版本升级后topLayoutGuide不再是UIView make.bottom.equalTo(self.view.mas_bottom).with.offset(-(self.bottomLayoutGuide.length)); NSLog(@"[updateViewConstraints] bottom: %g", self.bottomLayoutGuide.length); }]; #endif [super updateViewConstraints]; }
|
方式一. 直接使用UIViewController的topLayoutGuide.length
1 2 3 4 5 6 7 8
| [_topView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); }]; [_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); }];
|
方式二. 使用mas_topLayoutGuide和mas_bottomLayoutGuide
1 2 3 4 5 6 7 8 9 10
| [_topView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); make.top.equalTo(self.mas_topLayoutGuide); }]; [_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); make.bottom.equalTo(self.mas_bottomLayoutGuide); }];
|
三. UITabview cell height 计算方式
方式一. iOS 8 的Self-sizing特性
1 2 3 4 5 6
| _tableView.estimatedRowHeight = 80.0f;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return UITableViewAutomaticDimension; }
|
方式二. 调用systemLayoutSizeFittingSize:获取高度.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (!_templateCell) { _templateCell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([Case4Cell class])]; } // 获取对应的数据 Case4DataEntity *dataEntity = _data[(NSUInteger) indexPath.row]; // 判断高度是否已经计算过 if (dataEntity.cellHeight <= 0) { // 填充数据 [_templateCell setupData:dataEntity]; // 根据当前数据,计算Cell的高度,注意+1 dataEntity.cellHeight = [_templateCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 0.5f; NSLog(@"Calculate: %ld, height: %g", (long) indexPath.row, dataEntity.cellHeight); } else { NSLog(@"Get cache: %ld, height: %g", (long) indexPath.row, dataEntity.cellHeight); } return dataEntity.cellHeight; }
|
注意: 计算UILabel的preferredMaxLayoutWidth值,多行时必须设置这个值,否则系统无法决定Label的宽度
1 2 3 4
| CGFloat preferredMaxWidth = [UIScreen mainScreen].bounds.size.width - 44 - 4 * 3; _contentLabel.preferredMaxLayoutWidth = preferredMaxWidth;
[_contentLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
|
四. 确定当前ViewController显示的范围
方式1. 直接使用length值做约束
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
| [_topView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); }];
[_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); }];
// handler called updateViewConstraints
- (void)updateViewConstraints { // 根据新的length值更新约束 [_topView mas_updateConstraints:^(MASConstraintMaker *make) { // 直接利用其length属性,避免iOS、SDK版本升级后topLayoutGuide不再是UIView make.top.equalTo(self.view.mas_top).with.offset(self.topLayoutGuide.length); NSLog(@"[updateViewConstraints] top: %g", self.topLayoutGuide.length); }];
// 根据新的length值更新约束 [_bottomView mas_updateConstraints:^(MASConstraintMaker *make) { // 直接利用其length属性,避免iOS、SDK版本升级后topLayoutGuide不再是UIView make.bottom.equalTo(self.view.mas_bottom).with.offset(-(self.bottomLayoutGuide.length)); NSLog(@"[updateViewConstraints] bottom: %g", self.bottomLayoutGuide.length); }]; [super updateViewConstraints]; }
|
方式2. 使用新的mas_topLayoutGuide和mas_bottomLayoutGuide
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| [_topView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); make.top.equalTo(self.mas_topLayoutGuide); }];
[_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.equalTo(@40); make.left.and.right.equalTo(self.view); make.bottom.equalTo(self.mas_bottomLayoutGuide); }];
// Event called updateViewConstraints (可选)
- (void)updateViewConstraints { [super updateViewConstraints]; }
|
五. 引用MASConstraint
1 2 3 4 5 6 7 8 9 10
| // one : 创建一个引用 @property (strong, nonatomic) MASConstraint *constraint; // two : 赋值 [view mas_makeConstraints:^(MASConstraintMaker *make) { make.left.and.right.equalTo(self.view); make.top.equalTo(self.mas_topLayoutGuideBottom); _constraint = make.height.equalTo(@(value ...)); }]; // three : 更新约束的值 _constraint.equalTo(@(ohter value...));
|
此外还可以这么操作:
1 2 3 4
| // 卸载这根儿约束 [_constraint uninstall]; // 在把这根儿约束填上 [_constraint install];
|
更新UITabelViewCell的高度的两种方式:
- 刷新方法1
1 2 3
| [_tableView beginUpdates]; [_tableView endUpdates];
|
- 刷新方法2
1 2
| // 先重新计算高度,然后reload,不是原来的cell实例 [_tableView reloadRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationFade];
|
最后还可以通过下面的方式来展示更新的效果
1
| [_tableView scrollToRowAtIndexPath:index atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
|
六. 巧用优先级保证内容可见
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
| // _containerView 中包含了一个 支持滑动的_tipLabel // step one : [_tipLabel mas_makeConstraints:^(MASConstraintMaker *make) { // 设置边界条件约束,保证内容可见,优先级1000 make.left.greaterThanOrEqualTo(_containerView.mas_left); make.right.lessThanOrEqualTo(_containerView.mas_right); make.top.greaterThanOrEqualTo(_containerView.mas_top); make.bottom.lessThanOrEqualTo(_containerView.mas_bottom); // 优先级要比边界条件低750 _leftConstraint = make.centerX.equalTo(_containerView.mas_left).with.offset(50).priorityHigh(); // 优先级要比边界条件低750 _topConstraint = make.centerY.equalTo(_containerView.mas_top).with.offset(50).priorityHigh(); make.width.mas_equalTo(CGRectGetWidth(_tipLabel.frame) + 8); make.height.mas_equalTo(CGRectGetHeight(_tipLabel.frame) + 4); }];
// setp two UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWithGesture:)]; [_containerView addGestureRecognizer:pan];
// setp three - (void)panWithGesture:(UIPanGestureRecognizer *)pan { CGPoint touchPoint = [pan locationInView:_containerView]; _logLabel.text = NSStringFromCGPoint(touchPoint); _leftConstraint.offset = touchPoint.x; _topConstraint.offset = touchPoint.y; }
|
七. 约束生效时机(以动画为例)
创建一个承载改变约束的视图View
1
| @property (nonatomic, strong) UILabel *animationLabel;
|
设置最初的位置
1 2 3 4 5 6 7 8 9
| // 有个引用约束的前提 @property (nonatomic, strong) MASConstraint *centerXConstraint; // 设置最初的位置 [_animationLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.width.equalTo(@(200)); make.height.equalTo(@(40)); _centerXConstraint = make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); }];
|
核心, 查看约束生效时机带来的动画效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| - (void)action:(id)sender { // 设置初始状态 _centerXConstraint.equalTo(@(-CGRectGetWidth(self.view.frame))); // 立即让约束生效 [self.view layoutIfNeeded]; // 设置动画约束 _centerXConstraint.equalTo(@0); // 动画生效 [UIView animateWithDuration:0.3f animations:^{ [self.view layoutIfNeeded]; }]; }
|