iOS Masonry使用笔记

关于在使用Masonry中遇到的问题

一、约束警告

[LayoutConstraints] Unable to simultaneously satisfy constraints.

Probably at least one of the constraints in the following list is one you don't want. 
	Try this: 
		(1) look at each constraint and try to figure out which you don't expect; 
		(2) find the code that added the unwanted constraint or constraints and fix it. 
(
****
)
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

上面的问题是由于系统判定代码和编辑器中可能出现了重复约束,可以不做处理,跳过!。

刚开始的时候没有理解重复约束,因为感觉约束的没有毛病。后来才发现,因为cell的高度是根据约束变化,对于固定高度的cell,我约束了某个控件的topleftbottomrightheight,系统判定的原因可能在于已经约束了topbottom,那么对于height就没有必要约束,属于重复约束。

解决办法:设置优先级即可

make.height.mas_equalTo(75).priorityHigh();

关于Masonry中优先级的确定,如下图:

如图中topleftbottomrightheight,我们优先考虑使得此控件所有的约束成立且有效,确保此控件的位置大小。

  • 假设1:只设置topleftbottomright那么这个控件的约束是有问题的,因为父视图没有确定的高度。

  • 假设2:只设置topleftbottomheight,控件的位置就很确定了,所有约束均有效!

由此显而易见,对于此控件而言height的优先级最高。

二、极限值设置greaterThanOrEqualTo 和 lessThanOrEqualTo

使用到的场景还挺多的。举个例子,一个聊天输入框,高度可变,但是需要设置一个最高高度和最低高度。这时候使用这两个属性就很方便了。

greaterThanOrEqualTo大致的意思是约束的内容,不会低于设置的极限值。如:

1. 高度不低于40
make.height.mas_greaterThanOrEqualTo(40);
2. 还可以这样约束
make.left.mas_greaterThanOrEqualTo(self.lastView.mas_right);

lessThanOrEqualTogreaterThanOrEqualTo相反,约束的内容,不会高于设置的极限值

三、单边圆角设置

对于某个使用Masonry约束的控件,设置全角很简单。但是使用Masonry设置单边圆角,总是设置不成功,其实只是需要一个时机,在约束完之后,执行layoutIfNeeded再设置圆角即可!如:

[self.demoView mas_updateConstraints:^(MASConstraintMaker *make) {
    make.left.right.top.bottom.mas_equalTo(self);
}];

// 关键是这句
[self.demoView layoutIfNeeded];

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.demoView.bounds byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(5, 5)];// 圆角大小
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.demoView.bounds;
maskLayer.path = maskPath.CGPath;
self.demoView.layer.mask = maskLayer;

四、比例设置

[self.demoView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.left.right.mas_equalTo(self.contentView);
    make.height.mas_equalTo(self.demoView.mas_width).multipliedBy(3/4.);
}];

上面约束意思是高和宽遵循3:4的比例

五、Masonry约束UILabel,多行内容展示不全,显示…

有些情况我们需要UILabel展示多行完整的内容,但是约束没问题,展示效果上偶尔展示完整,偶尔展示不全。如在UITableview中,UILabel的内容首次展示不全,下拉刷新就展示完整了。

搜的结果基本以下两种:

  • 需要设置preferredMaxLayoutWidth,大多数的文章都是这个说法。但实际结果是设置了preferredMaxLayoutWidth,UILabel内容还是展示不全

  • 还有就是设置setContentCompressionResistancePriority:forAxis:,这种说法比较少

但实际运行中,将这两种方式配合起来,发现还是展示不全。

正确的解决办法:设置adjustsFontSizeToFitWidth。如:

self.titleLabel.numberOfLines = 0;
self.titleLabel.preferredMaxLayoutWidth = 200;
[self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
self.titleLabel.adjustsFontSizeToFitWidth = YES;

六、约束自定义的tableHeaderView,实现header高度自适应

第一步:设置UITableViewtableHeaderView,并给自定义的tableHeaderView添加宽度约束,这里必须要约束宽度

/// 必须先设置tableHeaderView = headerview
self.tableView.tableHeaderView = self.headerView;
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.width.equalTo(self.tableView);
}];

第二步:更新frame并重新设置tableHeaderView

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    OutpatientDepatmentHeaderView *header = (OutpatientDepatmentHeaderView *)self.tableView.tableHeaderView;
    if (!header) {
        return;
    }
    CGSize size = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    if (header.frame.size.height != size.height) {
        CGRect frame = header.frame;
        frame.size.height = size.height;
        header.frame = frame;
        self.tableView.tableHeaderView = header;
    }
}

第二步是很重要的一步,里面的方法只能在viewDidLayoutSubviews,否则会引起tableHeaderView遮挡住第一个cell,进而引发如下报错:

[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window........

这个报错是由于tableHeaderView遮挡住了cell,执行reloadData引起的。这种情况下被遮挡的cel其实是不可见的,不能reloadData

七、有意思的点

self.demoImageView = [[UIImageView alloc] init];
self.demoImageView.userInteractionEnabled = YES;
[self.view addSubview:self.demoImageView];
                
[self.demoImageView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.mas_equalTo(self.view).offset(7);
    make.left.mas_equalTo(self.view).offset(7);
}];

上面是对图片的约束,发现我没有约束宽高,在加载成功之后,会自动加一个宽高的约束,宽高等于图片真实的size。就想能不能有什么属性或设置可以设置个宽高的最大值?让图片可以显示在可见的控件范围内,后来没找到相关的方法,后来明了!

// 方式一,重点是这种
self.demoImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"demo"]];
        
// 方式二,同一差不多
self.demoImageView = [[UIImageView alloc] init];
self.demoImageView.image = [UIImage imageNamed:@"demo"];

看完这种初始化方式之后瞬间明了,系统自动加宽高理所当然啊,所以按即定的宽自适应高度显示,突然变得不可能了。还是得在设置图片之后,再修改size啊!!!摆脱不了计算的命运!!!

猜你喜欢

转载自blog.csdn.net/king6188/article/details/131314668