自動布局之-NSLayoutConstraint


AutoLayout概念是蘋果自iOS6開始引入的概念。
目前為止,實現自動布局技術選型方面也可以使用xib和storyboard。在開發過程中通常登錄、注冊等變動可能性較小的視圖,我會采用xib開發,其他頁面通常會采用Masonry布局。xib和手碼各有優勢,視情況而定。
 
關於NSLayoutAttributeLeading和NSLayoutAttributeTrailing,前邊和后邊並不是總是為左邊和右邊的,有些國家的前邊是右邊后邊是左邊所以這樣設定是為了國際化考慮。還有視圖基准線NSLayoutAttributeBaseline通常是指視圖的底部放文字的地方。
 
使用NSLayoutConstraint之前,我們需要確定一點:為了防止constraint和view本身的autoresizing屬性沖突,我們需要設置view的屬性:
view.translatesAutoresizingMaskIntoConstraints = NO;

一、UIKit框架提供的自動布局的方法一,詳細請看參數介紹:

/**
 設置約束

 @param view1 指定需要添加約束的視圖一
 @param attr1 指定視圖一需要約束的屬性
 @param relation 指定視圖一和視圖二添加約束的關系
 @param view2 指定視圖一依賴關系的視圖二;可為nil
 @param attr2 指定視圖一所依賴的視圖二的屬性,若view2=nil,該屬性設置 NSLayoutAttributeNotAnAttribute
 @param multiplier 系數   情況一和二為親測
                 情況一:設置A視圖的高度 = A視圖高度 * multiplier + constant;此時才會起作用;
                 情況二:設置A視圖和其他視圖的關系或 toItem=nil,multiplier設置不等於0即可,若等於0會crash;
 @param c 常量
 @return 返回生成的約束對象
 */
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

以上函數設置的約束等價於   view1.att1 =(以等號舉栗子,relation可> < ≥≤)view2.attr2 * multiplier + c;

簡單小需求:隨意在控制器中添加一個紅色view:

// 設置 redView 的寬 = 100.f * 1.f
    NSLayoutConstraint *redViewWidthConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeWidth
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.f
                                  constant:100.f];
    // 設置 redView 的高 = 100.f * 1.f
    NSLayoutConstraint *redViewHeightConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeHeight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.f
                                  constant:100.f];
    // 設置 redView 的前面(左邊) = self.view.leading + 20.f
    NSLayoutConstraint *redViewleadingConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeLeading
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.view
                                 attribute:NSLayoutAttributeLeading
                                multiplier:1.f
                                  constant:20.f];
    
    // 設置 redView 的頂部
    NSLayoutConstraint *redViewTopConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.view
                                 attribute:NSLayoutAttributeTop
                                multiplier:1.f
                                  constant:30.f];
    [self.view addConstraint:redViewWidthConstraint];
    [self.view addConstraint:redViewHeightConstraint];
    [self.view addConstraint:redViewleadingConstraint];
    [self.view addConstraint:redViewTopConstraint];

 

小注:
1、關於參數  multiplier 
✅舉個栗子🌰:
     [NSLayoutConstraint constraintWithItem:aView
     attribute:NSLayoutAttributeHeight
     relatedBy:NSLayoutRelationEqual
     toItem:aView
     attribute:NSLayoutAttributeWidth
     multiplier:2.f
     constant:100.f];
     等價於  aView的高 = aView的寬 * 2.f + 100.f;

 

2、❌本來想逃懶,下面的寫法,經過我實驗是錯誤的

     [NSLayoutConstraint constraintWithItem:self.redView
     attribute:NSLayoutAttributeWidth | NSLayoutAttributeHeight
     relatedBy:NSLayoutRelationEqual
     toItem:nil
     attribute:NSLayoutAttributeNotAnAttribute
     multiplier:1.f
     constant:100.f];

 

二、UIKit框架提供的自動布局的方法二,VFL語言來實現自動布局:

/**
 Description

 @param format VFL語句,舉個栗子:@"H:|-[_redView]-padding-|"
 @param opts 枚舉參數,默認寫0
 @param metrics 字典,key值為VFL語句中的變量 padding,value為指定的值: @{@"padding" : @50}
 @param views VFL語句中使用到的視圖
 */

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
舉個栗子:
NSArray *constraints1 =
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_redView]-padding-|"
                                            options:0
                                            metrics:@{@"padding" : @50}
                                              views:NSDictionaryOfVariableBindings(_redView)];
    NSArray *constraint2 =
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-height-[_redView(height)]"
                                            options:0
                                            metrics:@{@"height" : @20}
                                              views:NSDictionaryOfVariableBindings(_redView)];
    [self.view addConstraints:constraints1];
    [self.view addConstraints:constraint2];

 

關於UILabel自動布局,需要注意的是若label多行顯示,可通過設置numberOfLines:

UILabel *label = [[UILabel alloc] init];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    label.text = @"Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~";
    label.textColor = [UIColor blackColor];
    label.backgroundColor = [UIColor redColor];
    label.numberOfLines = 0;
    [self.view addSubview:label];
    
    NSArray *labelConstraintsH =
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[label]-20-|"
                                            options:0
                                            metrics:nil
                                              views:NSDictionaryOfVariableBindings(label)];
    NSArray *labelConstraintsV =
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[label]"
                                            options:0
                                            metrics:nil
                                              views:NSDictionaryOfVariableBindings(label)];
    [self.view addConstraints:labelConstraintsH];
    [self.view addConstraints:labelConstraintsV];

注意:
     1、VFL語句中具體浮點型不可以使用 56.f 諸如此類,會crash;
     2、VFL語句中的視圖,不要使用self.xxx屬性,而要使用變量_xxx,會crash
     3、addConstraint之前,必須保證subView已擁有superView
     4、視圖的 translatesAutoresizingMaskIntoConstraints 必須設置為NO,
 
 
結語:項目開發過程中,通常使用的是Masonry\SnapKit自動布局的三方庫,簡單高效。校之frame布局,自動布局更適合業務拓展。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM