如何搞定Autolayout,遠(yuǎn)離自動(dòng)布局帶給你的煩惱

首先讓我們了解一下什么是Autolayout

  • Autolayout是一種“自動(dòng)布局”技術(shù),專門用來布局UI界面的
  • Autolayout自iOS 6開始引入,由于Xcode 4的不給力,當(dāng)時(shí)并沒有得到很大推廣
  • 自iOS 7(Xcode 5)開始,Autolayout的開發(fā)效率得到很大的提升
  • 蘋果官方也推薦開發(fā)者盡量使用Autolayout來布局UI界面
  • Autolayout能很輕松地解決屏幕適配的問題

(一)下面讓我們用例子來進(jìn)一步了解Autolayout

示例如下:


效果圖.png

代碼實(shí)現(xiàn)Autolayout的步驟

  • 利用NSLayoutConstraint類創(chuàng)建具體的約束對(duì)象
  • 添加約束對(duì)象到相應(yīng)的view上
  - (void)addConstraint:(NSLayoutConstraint *)constraint;
  - (void)addConstraints:(NSArray *)constraints;

代碼實(shí)現(xiàn)Autolayout的注意點(diǎn)

  • 要先禁止autoresizing功能,設(shè)置view的下面屬性為NO
view.translatesAutoresizingMaskIntoConstraints = NO;
  • 添加約束之前,一定要保證相關(guān)控件都已經(jīng)在各自的父控件上
  • 不用再給view設(shè)置frame

創(chuàng)建約束對(duì)象的常用方法

創(chuàng)建約束對(duì)象的常用方法
+(id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
view1 :要約束的控件
attr1 :約束的類型(做怎樣的約束)
relation :與參照控件之間的關(guān)系
view2 :參照的控件
attr2 :約束的類型(做怎樣的約束)
multiplier :乘數(shù)
c :常量

要用蘋果的方法代碼實(shí)現(xiàn)如下:(額,敲得我【惡心他媽給惡心開門----惡習(xí)到家了,不過不要擔(dān)心請(qǐng)接著往下看】)


#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    // 禁止Autoresizing轉(zhuǎn)為Autolayout的約束
    blueView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:blueView];
    
    
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    // 禁止Autoresizing轉(zhuǎn)為Autolayout的約束
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:redView];
 
    // 添加藍(lán)色控件的約束
    NSLayoutConstraint *blueLeftLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20];
       [self.view addConstraint:blueLeftLc];
    NSLayoutConstraint *blueBottomLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20];
    [self.view addConstraint:blueBottomLc];
    
    NSLayoutConstraint *buleRightLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:-20];
    [self.view addConstraint:buleRightLc];
    
    NSLayoutConstraint *blueHLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:40];
    [self.view addConstraint:blueHLc];
    
    NSLayoutConstraint *blueWidthLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0];
    [self.view addConstraint:blueWidthLc];

    /*** 添加紅色控件的約束 ***/
    NSLayoutConstraint *redTopLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
    [self.view addConstraint:redTopLc];
    
    NSLayoutConstraint *redBottomLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
    [self.view addConstraint:redBottomLc];
    
    NSLayoutConstraint *redRightLc = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20];
    [self.view addConstraint:redRightLc];
}


@end

OK看到就這么一個(gè)簡單的效果要這么多代碼,是不是想要抓狂,不要心慌,下面我們介紹目前最流行的Autolayout第三方框架---Masonry

同樣的讓我們先大致了解一個(gè)Masonry的一些情況

  • 目前最流行的Autolayout第三方框架

  • 用優(yōu)雅的代碼方式編寫Autolayout

  • 省去了蘋果官方惡心的Autolayout代碼

  • 大大提高了開發(fā)效率

  • 框架地址:
    https://github.com/SnapKit/Masonry

上面的效果圖用Masonry實(shí)現(xiàn)如下:

#import "ViewController.h"

//define this constant if you want to use Masonry without the 'mas_' prefix
#define MAS_SHORTHAND

//define this constant if you want to enable auto-boxing for default syntax
#define MAS_SHORTHAND_GLOBALS

#import "Masonry.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    // 創(chuàng)建藍(lán)色View
    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:blueView];
    
    // 創(chuàng)建紅色View
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    
    // 給藍(lán)色View添加約束
    [blueView makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view.left).offset(20);
        make.bottom.equalTo(self.view.bottom).offset(-20);
        make.right.equalTo(redView.left).offset(-20);
        make.height.equalTo(40);
        make.width.equalTo(redView.width);
        
    }];
    
    // 給紅色View添加約束
    [redView makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.view.right).offset(-20);
        make.top.equalTo(blueView.top);
        make.bottom.equalTo(blueView.bottom);
   
    }];
    
    // 更新約束
    [blueView updateConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(80);
    }];
}

@end


上面這段代碼是不是讓你的心情大爽了呢,激動(dòng)之余細(xì)心的讀者可能發(fā)現(xiàn),咦#import "Masonry.h"上面怎么有兩個(gè)宏呢,下面我們來了解一下這是為什么呢

首先是Masonry中的mas_equalToequalTo

  • 默認(rèn)情況下

    • mas_equalTo有自動(dòng)包裝功能,比如自動(dòng)將20包裝為@20
    • equalTo沒有自動(dòng)包裝功能
  • 如果添加了下面的宏,那么mas_equalTo和equalTo就沒有區(qū)別

#define MAS_SHORTHAND_GLOBALS
// 注意:這個(gè)宏一定要添加到#import "Masonry.h"前面

其次是Masonry中的mas_widthwidth

  • 默認(rèn)情況下

    • width是make對(duì)象的一個(gè)屬性,用來添加寬度約束用的,表示對(duì)寬度進(jìn)行約束
    • mas_width是一個(gè)屬性值,用來當(dāng)做equalTo的參數(shù),表示某個(gè)控件的寬度屬性
  • 如果添加了下面的宏,mas_width也可以寫成width

 #define MAS_SHORTHAND

 mas_height、mas_centerX以此類推

總之這樣簡單高效的方法讓我們程序員用的好爽不是嗎

(二)開發(fā)中我們會(huì)遇到這樣的問題- 使用到約束的優(yōu)先級(jí)

  • 為了大家更方便的學(xué)習(xí)我就不用代碼實(shí)現(xiàn)了,在Storyboard中添加約束
  • 先看一下效果圖
// 點(diǎn)擊屏幕時(shí)會(huì)調(diào)用此方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //
    [self.blueView removeFromSuperview];
    // 利用2s的時(shí)間去更新約束,在修改了約束之后,只要執(zhí)行下面代碼,就能做動(dòng)畫效果,感興趣的讀者可以試一下
    [UIView animateWithDuration:2 animations:^{
      
        // 強(qiáng)制更新約束(讓self.view以及它的所有子控件都強(qiáng)制更新)
        [self.view layoutIfNeeded];
    }];
   
}
約束優(yōu)先級(jí).gif

OK這樣的效果怎么實(shí)現(xiàn)呢,給大家看兩張圖大家就明白約束優(yōu)先級(jí)的用處了

  • 綠色與藍(lán)色的約束優(yōu)先級(jí)值


    綠色與藍(lán)色的約束優(yōu)先級(jí)值.png
  • 綠色與紅色的約束優(yōu)先級(jí)值
綠色與紅色的約束優(yōu)先級(jí)值.png
  • 從上面可以看出綠色與藍(lán)色的約束優(yōu)先級(jí)值大于綠色與紅色的約束優(yōu)先級(jí)值,所以當(dāng)3個(gè)View都存在時(shí)執(zhí)行綠色與藍(lán)色的約束優(yōu)先級(jí)值,
    當(dāng)點(diǎn)擊屏幕,移除綠色View時(shí)綠色與藍(lán)色的約束優(yōu)先級(jí)值無效了,執(zhí)行綠色與紅色的約束優(yōu)先級(jí)值,故此可以實(shí)現(xiàn)以上效果

謝謝各位耐心觀看,如有問題請(qǐng)留言我會(huì)及時(shí)更新改正,謝謝大家,祝各位每天開心!??!

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容