iOS開發之 Autolayout 詳解

2018-05-24-1_HemKn1OC2bh7tUpK7_p0Ng

iOS開發之 Autolayout 詳解

1. 概述

  1. Autolayout 是 Apple 自 iOS6 開始引入的旨在解決不一樣屏幕之間佈局適配的技術
  2. 蘋果官方推薦開發者使用 Autolayout 進行UI界面的佈局
  3. Autolayout 有兩個核心概念:1. 參照。 2. 約束
  4. 使用Autolayout的注意點:
    1. 添加約束以前須要保證控件已被添加到父控件中
    2. 不須要再給View設置frame
    3. 禁止 autoresizing 功能。

2. 代碼實現 Autolayout

2.1 步驟:

  1. 把 View 添加到父控件上。git

  2. 添加約束到相應的 View 上。github

    - (void)addConstraint:(NSLayoutConstraint *)constraint;
    - (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints;
    複製代碼
  3. 自動佈局核心公式: obj1.property1 =(obj2.property2 * multiplier)+ constant valueobjective-c

NSLayoutConstraint
/**
view1 :要約束的控件
attr1 :約束的類型(作怎樣的約束)
relation :與參照控件之間的關係
view2 :參照的控件
attr2 :約束的類型(作怎樣的約束)
multiplier :乘數
c :常量
*/
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
複製代碼

2.2 實例

添加一個左間距100 上間距200,寬150 高64 的紅視圖:
- (void)testAutolayout1 {
    UIView *redV = [[UIView alloc] init];
    redV.backgroundColor = [UIColor redColor];
    redV.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:redV];
    /**
     view1 :要約束的控件
     attr1 :約束的類型(作怎樣的約束)
     relation :與參照控件之間的關係
     view2 :參照的控件
     attr2 :約束的類型(作怎樣的約束)
     multiplier :乘數
     c :常量
     */
    /// 左間距100:
    NSLayoutConstraint *consLeft = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:100];
    [self.view addConstraint:consLeft];
    
    /// 上間距200:
    NSLayoutConstraint *consTop = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:200];
    [self.view addConstraint:consTop];
    
    /// 寬150:
    NSLayoutConstraint *consWidth = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1.0 constant:150];
    [redV addConstraint:consWidth];
    
    /// 高64:
    NSLayoutConstraint *consHeight = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0 constant:64];
    [redV addConstraint:consHeight];
}
複製代碼
在上視圖基礎上添加一個與紅視圖右間距相同,高度相同,頂部距離紅色視圖間距20,寬度爲紅色視圖一半的藍色View
UIView *blueV = [[UIView alloc] init];
    blueV.backgroundColor = [UIColor blueColor];
    blueV.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:blueV];
    
    /// 和 redV 右間距爲0
    NSLayoutConstraint *b_consRight = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0];
    [self.view addConstraint:b_consRight];
    
    /// 和 redV 等高
    NSLayoutConstraint *b_consHeight = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0];
    [self.view addConstraint:b_consHeight];
    
    /// 寬度是 redV 的一半
    NSLayoutConstraint *b_consWidth = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
    [self.view addConstraint:b_consWidth];
    
    /// 頂部距離 redV 20
    NSLayoutConstraint *b_consTop = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20.0];
    [self.view addConstraint:b_consTop];
複製代碼

最終效果: ide

屏幕快照 2018-05-24 下午3.46.26

2.3 添加約束的規則

在建立約束以後,須要將其添加到做用的view上。 在添加時要注意目標view須要遵循如下規則:佈局

#####(1)對於兩個同層級view之間的約束關係,添加到它們的父view上 #####(2)對於兩個不一樣層級view之間的約束關係,添加到他們最近的共同父view上 #####(3)對於有層次關係的兩個view之間的約束關係,添加到層次較高的父view上flex

3. VFL

VFL全稱是Visual Format Language,翻譯過來是「可視化格式語言」,是蘋果公司爲了簡化Autolayout的編碼而推出的抽象語言。編碼

/*
     format :VFL語句
     opts :約束類型
     metrics :VFL語句中用到的具體數值
     views :VFL語句中用到的控件
     */
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *,id> *)views;
複製代碼

@{@"redV" : redV} 等價於 NSDictionaryOfVariableBindings(redV)spa

NSDictionary *views =

NSDictionaryOfVariableBindings(blueView, redView);

NSArray *conts2 =

[NSLayoutConstraint constraintsWithVisualFormat:

@"V:[blueView(==blueHeight)]-margin-|" options:0 metrics:

@{@"blueHeight" : @40, @"margin" : @20} views:views];
複製代碼

約束格式說明:

水平方向        H: 垂直方向        V: Views         [view] SuperView      | 關係         >=,==,<= 空間,間隙       - 優先級        @value翻譯

3.1 VFL 部分語法:

H:|-100-[redV(200)]-|

水平方向距離左邊距100,寬度2003d

V:|-200-[redV(64)]-|

垂直方向距離頂部200,高度64

H:[redV(72)]-12-[blueV(50)]

水平方向redV 寬度72,blueV 寬度50,他們之間間距12

H:[redV(>=60@700)]

水平方向redV寬度大於等於60,優先級爲700 (優先級最大1000)

V:[redBox]-[yellowBox(==redBox)]

豎直方向上,先有一個redBox,其下方緊接一個高度等於redBox高度的yellowBox

H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|

水平方向上,Find距離父view左邊緣默認間隔寬度,以後是FindNext距離Find間隔默認寬度;再以後是寬度不小於20的FindField,它和FindNext以及父view右邊緣的間距都是默認寬度。(豎線「|」 表示superview的邊緣)

3.2 VFL的語法

  • 標準間隔:[button]-[textField]
  • 寬約束:[button(>=50)]
  • 與父視圖的關係:|-50-[purpleBox]-50-|
  • 垂直佈局:V:[topField]-10-[bottomField]
  • Flush Views:[maroonView][buleView]
  • 權重:[button(100@20)]
  • 等寬:[button(==button2)]
  • Multiple Predicates:[flexibleButton(>=70,<=100)]

注意事項

建立這種字符串時須要注意一下幾點:

  • H:和V:每次都使用一個。
  • 視圖變量名出如今方括號中,例如[view]。
  • 字符串中順序是按照從頂到底,從左到右
  • 視圖間隔以數字常量出現,例如-10-。
  • |表示父視圖

3.3 使用Auto Layout時須要注意的點

  • 注意禁用Autoresizing Masks。對於每一個須要使用Auto Layout的視圖須要調用setTranslatesAutoresizingMaskIntoConstraints:NO
  • VFL語句裏不能包含空格和>,<這樣的約束
  • 佈局原理是由外向里布局,最早屏幕尺寸,再一層一層往裏決定各個元素大小。
  • 刪除視圖時直接使用removeConstraint和removeConstraints時須要注意這樣刪除是無法刪除視圖不支持的約束致使view中還包含着那個約束(使用第三方庫時須要特別注意下)。解決這個的辦法就是添加約束時用一個局部變量保存下,刪除時進行比較刪掉和先前那個,還有個辦法就是設置標記,constraint.identifier = @「What you want to call」。

3.4 佈局約束規則

表達佈局約束的規則可使用一些簡單的數學術語,以下表

類型 描述
屬性 視圖位置 NSLayoutAttributeLeft, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom
屬性 視圖前面後面 NSLayoutAttributeLeading, NSLayoutAttributeTrailing
屬性 視圖的寬度和高度 NSLayoutAttributeWidth, NSLayoutAttributeHeight
屬性 視圖中心 NSLayoutAttributeCenterX, NSLayoutAttributeCenterY
屬性 視圖的基線,在視圖底部上方放置文字的地方 NSLayoutAttributeBaseline
屬性 佔位符,在與另外一個約束的關係中沒有用到某個屬性時可使用佔位符 NSLayoutAttributeNotAnAttribute
關係 容許將屬性經過等式和不等式相互關聯 NSLayoutRelationLessThanOrEqual, NSLayoutRelationEqual, NSLayoutRelationGreaterThanOrEqual
數學運算 每一個約束的乘數和相加性常數 CGFloat值

3.5 View的改變會調用哪些方法

  • 改變frame.origin不會掉用layoutSubviews
  • 改變frame.size會使 superVIew的layoutSubviews調用和本身view的layoutSubviews方法
  • 改變bounds.origin和bounds.size都會調用superView和本身view的layoutSubviews方法

3.6 VFL 實例:

- (void)testVFL {
    UIView *redV = [[UIView alloc] init];
    redV.backgroundColor = [UIColor redColor];
    redV.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:redV];
    
    UIView *blueV = [[UIView alloc] init];
    blueV.backgroundColor = [UIColor blueColor];
    blueV.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:blueV];
    /*
     format :VFL語句
     opts :約束類型
     metrics :VFL語句中用到的具體數值
     views :VFL語句中用到的控件
     */
    //水平方向 redV 左右間距爲20
    NSArray *cons1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[redV]-20-|" options:0 metrics:nil views:@{@"redV":redV}];
    [self.view addConstraints:cons1];
    
    //垂直方法redV距離頂部 100, redV 高度爲64, blueV頂部距離redV 100 像素, blueV的高度等於redV
    NSArray *cons2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-margin-[redV(64)]-margin-[blueV(==redV)]" options:NSLayoutFormatAlignAllRight metrics:@{@"margin" : @100} views:NSDictionaryOfVariableBindings(redV,blueV)];
    [self.view addConstraints:cons2];
    
    NSLayoutConstraint *cons = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
    [self.view addConstraint:cons];
}
複製代碼

運行結果:

2018-05-24_3.46.26

文中演示Demo 均已開源在 GitHub上,這是連接: XWAutolayoutDemo In Github

相關文章
相關標籤/搜索