1. 程式人生 > >iOS實戰之從左往右自動填充佈局頁面

iOS實戰之從左往右自動填充佈局頁面

這裡主要講的就是控制元件寬度可變時的計算:

方法一:
這裡使用一個寬度可變的Button,寬度不變的兩個Label從左往右依次排布來測試。這裡使用三組組合,每一組都用一個UIView包裹。

首先為了測試,Button的標題,依次為:

NSArray *btnTitle = @[@"我是一個長標題,很長很長很長很長的標題",@"我是短標題",@"標題"];

titleLB的文字:

titleLB.text = @"我是固定的標題";

flagLB的文字:

flagLB.text = @"立個flag";

接下來就是計算:
首先flagLB和titleLB的Size我們可以確定,可以給一個固定的值,也可以自動計算,由於button的title是可變的,所以我們採用自動計算

這裡計算,我們需要使用一個系統方法:

CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin 
  attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15
]} context:nil];

這樣就能計算一個文字的size,類似於iOS7以前使用的sizeWithFont,從這個Size可以獲取文字的寬高。

由於這三者的Size都確定了,佈局寫起來也就簡單了:

CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15
]} context:nil]; CGRect textRect2 = [titleLB.text boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:titleLB.font} context:nil]; [button mas_remakeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(bgView.mas_left).offset(5); make.centerY.equalTo(bgView); make.height.mas_equalTo(20); make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width)); }]; [titleLB mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(button.mas_right).offset(5); make.height.mas_equalTo(18); make.width.mas_equalTo(textRect2.size.width); make.centerY.mas_equalTo(bgView); }]; [flagLB mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(titleLB.mas_right).offset(5); make.size.mas_equalTo(CGSizeMake(60, 13)); make.centerY.mas_equalTo(bgView); }];

最關鍵的就是這句:
make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width));
可能有人會有疑問,這裡不是能獲得button的titleSize嗎,直接設定titleSize.width不就可以了嗎,如果這裡title非常長的話,那麼後面那兩個label就會頂出到螢幕外面,這個是不符合設計的,所以需要對button的寬度進行限制。這裡是對width進行判定,將titleSize和剩餘螢幕寬度進行比較,如果button長度小於螢幕剩餘寬度,則寬度為button的title寬度,如果button標題長度過長,則button的寬度為剩餘螢幕寬度。
最後上傳一個效果:

效果圖


方法二:
理論
- 約束優先順序: 在Autolayout中每個約束都有一個優先順序, 優先順序的範圍是1 ~ 1000。建立一個約束,預設的優先順序是最高的1000。
- Content Hugging Priority: 該優先順序表示一個控制元件抗被拉伸的優先順序。優先順序越高,越不容易被拉伸,預設是250。
- Content Compression Resistance Priority: 該優先順序和上面那個優先順序相對應,表示一個控制元件抗壓縮的優先順序。優先順序越高,越不容易被壓縮,預設是750


所以預設情況下兩邊的label的Content Hugging和Content Compression優先順序都是一樣的,為了讓右邊的label完全顯示,那麼我們需要增大右邊label的抗壓縮級,或者減小左邊label的抗壓縮級,總之是得讓右邊的抗壓縮級大於左邊的label,這樣才能讓右邊的label內容優先顯示。

UIView中關於Content Hugging 和 Content Compression Resistance的方法有:

- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);

- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);

程式碼:

    [self.leftLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.equalTo(self.view).offset(10);
        make.centerY.equalTo(self.view).offset(-50);
        make.right.mas_lessThanOrEqualTo(self.rightLB.mas_left);
    }];

    [self.rightLB mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.mas_greaterThanOrEqualTo(self.leftLB.mas_right);
        make.right.equalTo(self.view).offset(-10);
        make.centerY.equalTo(self.leftLB);
    }];

    [self.leftLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.equalTo(self.view).offset(10);
        make.centerY.equalTo(self.view).offset(50);
        make.right.mas_lessThanOrEqualTo(self.rightLB1.mas_left);
    }];

    [self.rightLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(30));
        make.left.mas_greaterThanOrEqualTo(self.leftLB1.mas_right);
        make.right.equalTo(self.view).offset(-10);
        make.centerY.equalTo(self.leftLB1);
    }];

    //讓左邊的label抗壓縮性降低,即可壓縮,越高越不容易被壓縮
    [self.leftLB1 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    /*
    或者讓左邊的label抗拉伸性增高,越高越不容易被拉伸
    [self.leftLB1 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    或者讓右邊的label抗壓縮性增高,即可擴張
    [self.rightLB1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    或者讓右邊的label抗拉伸性降低,即可擴張
    [self.rightLB1 setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
    */

最關鍵的註釋那幾句話,隨便選中一句都可以達到效果。

效果圖


最後:

附加一個很好用的相似佈局自動排列:

[self.container addSubview:self.label1];
[self.container addSubview:self.label2];
[self.container addSubview:self.label3];
//將控制元件新增到一個數組裡面
NSArray *array = @[self.label1,self.label2,self.label3]; 
/*
使用方法,一次性配置:橫向佈局,控制元件間距90,第一個控制元件與父容器間距15,
最後一個控制元件與父容器間距15
*/
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal 
withFixedSpacing:90 leadSpacing:15 tailSpacing:15];  

//設定單個view的大小,在父view的與需要平分的方向的垂直方向的位置,例如需要在水平方向平分,就給一個豎直方向的位置
[array mas_makeConstraints:^(MASConstraintMaker *make) {
  make.top.equalTo(@120);
  make.height.equalTo(@75);
}];

實現效果
效果