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.

上面的問題是由于系統(tǒng)判定代碼和編輯器中可能出現(xiàn)了重復約束,可以不做處理,跳過!。

剛開始的時候沒有理解重復約束,因為感覺約束的沒有毛病。后來才發(fā)現(xiàn),因為cell的高度是根據約束變化,對于固定高度的cell,我約束了某個控件的top、left、bottom、right、height,系統(tǒng)判定的原因可能在于已經約束了topbottom,那么對于height就沒有必要約束,屬于重復約束。

解決辦法:設置優(yōu)先級即可!

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

關于Masonry中優(yōu)先級的確定,如下圖:

如圖中top、left、bottom、right、height,我們優(yōu)先考慮使得此控件所有的約束成立且有效,確保此控件的位置大小。

  • 假設1:只設置top、leftbottom、right那么這個控件的約束是有問題的,因為父視圖沒有確定的高度。

  • 假設2:只設置top、left、bottom、height,控件的位置就很確定了,所有約束均有效!

由此顯而易見,對于此控件而言height的優(yōu)先級最高。

二、極限值設置greaterThanOrEqualTo 和 lessThanOrEqualTo

使用到的場景還挺多的。舉個例子,一個聊天輸入框,高度可變,但是需要設置一個最高高度和最低高度。這時候使用這兩個屬性就很方便了。

greaterThanOrEqualTo大致的意思是約束的內容,不會低于設置的極限值。如:

1. 高度不低于40
make.height.mas_greaterThanOrEqualTo(40);
2. 還可以這樣約束
make.left.mas_greaterThanOrEqualTo(self.lastView.mas_right);

lessThanOrEqualTogreaterThanOrEqualTo相反,約束的內容,不會高于設置的極限值

三、單邊圓角設置

對于某個使用Masonry約束的控件,設置全角很簡單。但是使用Masonry設置單邊圓角,總是設置不成功,其實只是需要一個時機,在約束完之后,執(zhí)行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:,這種說法比較少

但實際運行中,將這兩種方式配合起來,發(fā)現(xiàn)還是展示不全。

正確的解決辦法:設置adjustsFontSizeToFitWidth。如:

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

六、約束自定義的tableHeaderView,實現(xiàn)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,進而引發(fā)如下報錯:

[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,執(zhí)行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);
}];

上面是對圖片的約束,發(fā)現(xiàn)我沒有約束寬高,在加載成功之后,會自動加一個寬高的約束,寬高等于圖片真實的size。就想能不能有什么屬性或設置可以設置個寬高的最大值?讓圖片可以顯示在可見的控件范圍內,后來沒找到相關的方法,后來明了!

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

看完這種初始化方式之后瞬間明了,系統(tǒng)自動加寬高理所當然啊,所以按即定的寬自適應高度顯示,突然變得不可能了。還是得在設置圖片之后,再修改size?。。?!擺脫不了計算的命運?。?!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容