国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS AutoLayout

2019-11-09 15:05:33
字體:
來源:轉載
供稿:網(wǎng)友

原創(chuàng)作者鏈接:http://www.cocoachina.com/ios/20160616/16732.html謝謝

使用 Objective-C 純代碼編寫 AutoLayout,看 AutoLayout 的字面理解就是自動布局,聽起來好像蠻屌的樣子。說白了就是適配:適應、兼容各種不同的情況,包括不同版本的操作系統(tǒng)的適配(系統(tǒng)適配)和不同屏幕尺寸的適配(屏幕適配)。

Talk is cheap, show me the code

先說一下用代碼實現(xiàn) AutoLayout 步驟,別眨眼:

利用 NSLayoutConstraint 類創(chuàng)建具體的約束對象;

添加約束對象到相應的 view 上,代碼有這兩種:

12- (void)addConstraint:(NSLayoutConstraint *)constraint;- (void)addConstraints:(NSArray *)constraints;

或許有人問了,原來才兩個步驟就可以了,我剛剛褲子都脫了,你就給我看這個?!

話不多說,馬上 show you the code !

先看看我們使用 frame 的方式是如何確定一個 view 的位置的:

1234567- (void)viewDidLoad {    [super viewDidLoad];    self.title = @"使用 frame 的方式";    UIView *purpleView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 150, 150)];    purpleView.backgroundColor = [UIColor purpleColor];    [self.view addSubview:purpleView];}

代碼很簡單,運行效果如下:

a14b19283f9267d661cff15c4b33e21a1.jpg

運行效果

再來看看 AutoLayout 的實現(xiàn):

123456789101112131415161718192021- (void)viewDidLoad {    [super viewDidLoad];    self.title = @"使用 AutoLayout 的方式";    UIView *purpleView = [[UIView alloc] init];    purpleView.backgroundColor = [UIColor purpleColor];    // 禁止將 AutoresizingMask 轉換為 Constraints    purpleView.translatesAutoresizingMaskIntoConstraints = NO;    [self.view addSubview:purpleView];    // 添加 width 約束    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:purpleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:150];    [purpleView addConstraint:widthConstraint];    // 添加 height 約束    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:purpleView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:150];    [purpleView addConstraint:heightConstraint];    // 添加 left 約束    NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:purpleView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:100];    [self.view addConstraint:leftConstraint];    // 添加 top 約束    NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:purpleView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:200];    [self.view addConstraint:topConstraint];}

看完這段代碼,我收到了驚嚇!我被這一大段代碼嚇到了,很多童鞋看到那么簡單的布局需要寫那么多代碼,可能就被嚇跑了。我只能說一句:先不要走,待我慢慢解釋~

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

一個 NSLayoutConstraint 對象就代表一個約束。

1+ (id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

總共有 7 個參數(shù),那就以 leftConstraint 為例吧介紹這 7 個參數(shù)吧

view1: 要約束的控件(purpleView)

attr1: 約束的類型(常量),就是要做怎么樣的約束,大家可以進去看看都有什么常量(這里是NSLayoutAttributeLeft)

relation: 與參照控件之間的關系(常量),包括等于、大于等于、小于等于(NSLayoutRelationEqual 是指等于)

view2: 參照的控件(self.view)

attr2: 約束的類型(常量),就是要做怎么樣的約束,大家可以進去看看都有什么常量(這里是NSLayoutAttributeLeft)(NSLayoutAttributeLeft)

multiplier: 乘數(shù),就是多少倍(1.0)

c: 常量,做好了上述的約束之后會加上這個常量(100)

所以 leftConstraint 就是代表:要約束的控件purpleView 的左間距是等于參照控件 self.view 的左間距的 1.0 倍加上 100。

所以我們得出 AutoLayout 的核心計算公式:

1obj1.PRoperty1 =(obj2.property2 * multiplier)+ constant value

添加約束(addConstraint)的規(guī)則

在創(chuàng)建約束了之后,需要將其添加到作用的控件上才能生效,注意在添加約束的時候目標控件需要遵循以下規(guī)則(這里控件就用 view 簡單表示吧):

(1)對于兩個同層級 view 之間的約束關系,添加到它們的父 view 上

0acfe5ceff8183dd6add1a1a03b9bd311.png

(2)對于兩個不同層級 view 之間的約束關系,添加到他們最近的共同父 view 上

a37f88e70fa02a38f7038dcc48e5c4ac1.png

(3)對于有層次關系的兩個 view 之間的約束關系,添加到層次較高的父 view 上

(4)對于比如長寬之類的,只作用在該 view 自己身上的話,添加到該 view 自己上,不用圖了吧。

可以看出,widthConstraint 和 Constraint 屬于第(4)種,leftConstraint 和 rightConstraint 屬于第(3)種。

代碼實現(xiàn) AutoLayout 的注意事項

如果只是創(chuàng)建和添加了約束,是不能正常運行的,要做好以下的工作:

(1)要先禁止 autoresizing 功能,防止 AutoresizingMask 轉換成 Constraints,避免造成沖突,需要設置 view 的下面屬性為 NO:

1view.translatesAutoresizingMaskIntoConstraints = NO;

(2)添加約束之前,一定要保證相關控件都已經(jīng)在各自的父控件上。用上面的例子就是 [self.view addSubview:purpleView]; 一定要放在添加 left 約束之前,否則程序會 crash,因為要確保 purpleView 要已經(jīng)在 self.view 上了。建議先寫 [self.view addSubview:purpleView]; 之后,再專心寫約束。

(3)不用再給 view 設置 frame

看到了吧,那么簡單的一個界面,用 AutoLayout 實現(xiàn)的話竟然要那么多代碼,感覺上并沒有那么方便是吧?

其實 AutoLayout 要看應用內容決定,上面只是一個使用的 demo。如果你的內容是信息眾多,同時需要展示的類別也很多,尺寸動態(tài)不定,比如說微博列表、QQ 動態(tài)列表等等,寫這些復雜界面使用 AutoLayout 能給予(jǐ yǔ??)很大的幫助。

Apple 為了簡化 AutoLayout 復雜的代碼,開發(fā)了一種 VFL 語言(Visual format language),事實上沒看見簡化多少,而且還有比較大的局限性,這里就不介紹了,想了解的童鞋自己 Google 去。

算了,給個官方鏈接吧:Visual Format Language。

如何優(yōu)雅的代碼編寫 AutoLayout

看到了 Apple 自帶的 AutoLayout 實現(xiàn)方式,感覺實在是太惡心了,那么如何優(yōu)雅的代碼編寫 AutoLayout 呢?

—— 使用第三方框架 Masonry。GitHub: https://github.com/SnapKit/Masonry,看它的介紹,感覺挺牛掰的:

Harness the power of AutoLayout NSLayoutConstraints with a simplified, chainable and expressive syntax. Supports iOS and OSX Auto Layout.

看完 README.md 文件發(fā)現(xiàn)的確蠻優(yōu)雅的。

先一覽 Masonry 是如何實現(xiàn) AutoLayout 的:

12345678910111213141516#import "ViewController.h"#import "Masonry.h" // 第三方或自己寫的用引號,系統(tǒng)自帶用雙引號。@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    UIView *purpleView = [[UIView alloc] init];    purpleView.backgroundColor = [UIColor purpleColor];    [self.view addSubview:purpleView];    [purpleView mas_makeConstraints:^(MASConstraintMaker *make) {        // 在這個 block 里面,利用 make 對象創(chuàng)建約束        make.size.mas_equalTo(CGSizeMake(100, 100));        make.center.mas_equalTo(self.view);    }];}

運行效果:

f0e662e4940d2ef82ca3126dfd042e1d1.jpg

創(chuàng)建一個長和寬均為 100、與父 view 居中的 view

注意:purpleView.translatesAutoresizingMaskIntoConstraints = NO;不需要在這里寫了,因為 Masonry 已經(jīng)寫好了。

Masonry 開車,趕緊上車

一步一步跟著來,哈哈嘻嘻

1234567// 長寬均為 100,粘著父 view 右下角[purpleView mas_makeConstraints:^(MASConstraintMaker *make) {  make.width.equalTo(@100);  make.height.equalTo(@100);  make.right.equalTo(self.view);  make.bottom.equalTo(self.view);}];

3d2de2249bbce2dc71002d9a660691871.jpg

12345678910// 長寬均為 100,粘著父 view 右下角,間距為 16[purpleView mas_makeConstraints:^(MASConstraintMaker *make) {     make.width.equalTo(@100);     make.height.equalTo(@100);     // 這里也可以寫 make.right.equalTo(self.view.mas_right).offset(-16);     // 為了增強可讀性,可以在 .offset 前加上 .with 或者 .and: make.right.equalTo(self.view).with.offset(-16); 看自己習慣吧     make.right.equalTo(self.view).offset(-16);     // 這里也可以寫 make.right.equalTo(self.view.mas_bottom).offset(-16);     make.bottom.equalTo(self.view).offset(-16);}];

ffe8a036ebc5e2af719ae2d7de7a07a41.png

看到上面代碼的包裝好的 @100,其實也可以直接傳值 100,不過要把 equalTo 改成 mas_equalTo,這樣它就自動幫你包裝好了。

12make.width.mas_equalTo(100);make.height.mas_equalTo(100);

其實 mas_equalTo 就是一個宏,大家可以進去看看定義。

mas_equalTo 這個方法會對參數(shù)進行包裝

equalTo 這個方法不會對參數(shù)進行包裝

mas_equalTo 的功能強于 equalTo

大家可能會覺得有點兒暈,有時候用 mas_equalTo,有時候用 equalTo,其實大家可以在 pch 文件里定義兩個宏,就可以完美解決這個糾結問題。注意要寫在 #import "Masonry.h" 前面。

1234//define this constant if you want to use Masonry without the 'mas_' prefix,這樣子 `mas_width` 等就可以寫成 `width`#define MAS_SHORTHAND//define this constant if you want to enable auto-boxing for default syntax,這樣子 `mas_equalTo` 和 `equalTo` 就沒有區(qū)別了#define MAS_SHORTHAND_GLOBALS

好,現(xiàn)在來一個稍微比剛才的復雜一點點的界面:

1234567891011121314151617181920212223- (void)viewDidLoad {    [super viewDidLoad];    UIView *purpleView = [[UIView alloc] init];    purpleView.backgroundColor = [UIColor purpleColor];    [self.view addSubview:purpleView];    UIView *orangeView = [[UIView alloc] init];    orangeView.backgroundColor = [UIColor orangeColor];    [self.view addSubview:orangeView];    CGFloat margin = 16;    CGFloat height = 32;    [purpleView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view).offset(margin);        make.bottom.equalTo(self.view).offset(-margin);        make.right.equalTo(orangeView.left).offset(-margin);        make.height.equalTo(height);        make.width.equalTo(orangeView);    }];    [orangeView mas_makeConstraints:^(MASConstraintMaker *make) {        make.bottom.equalTo(self.view).offset(-margin);        make.right.equalTo(self.view).offset(-margin);        make.height.equalTo(height);    }];}

e5099c6e4323ef322a2a090b4a54a74e1.png

兩個等高等寬的 view 平分屏幕寬度,帶有間隙

其實實現(xiàn)這個界面有很多中寫法,大家可以試試,比如說這樣寫:

123456789101112131415- (void)viewDidLoad {    ...    [purpleView mas_makeConstraints:^(MASConstraintMaker *make) {        make.left.equalTo(self.view).offset(margin);        make.bottom.equalTo(self.view).offset(-margin);        make.right.equalTo(orangeView.left).offset(-margin);        make.height.equalTo(height);        make.height.equalTo(orangeView);        make.width.equalTo(orangeView);        make.top.equalTo(orangeView);    }];    [orangeView mas_makeConstraints:^(MASConstraintMaker *make) {        make.right.equalTo(self.view).offset(-margin);    }];}

總結

其實 Masonry 的文檔已經(jīng)很詳細了,建議大家去看文檔,我寫這個主要是為了做這個界面的 Tableview 上下拉阻尼效果而準備的

2fa28c46242fd7d36f67eeda5d55ecc81.png

對我粗暴~


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 苍南县| 曲周县| 平昌县| 兴化市| 柘荣县| 富宁县| 来安县| 元氏县| 潮州市| 鄯善县| 佛教| 白河县| 安达市| 普洱| 子洲县| 巴东县| 祁阳县| 宁晋县| 宁晋县| 武冈市| 潍坊市| 兰坪| 阜宁县| 万盛区| 离岛区| 铁岭市| 德安县| 剑河县| 和林格尔县| 来安县| 会同县| 卢氏县| 隆子县| 故城县| 大丰市| 乡城县| 慈利县| 青冈县| 资中县| 绍兴县| 长武县|