iOS自動適配

來源:互聯網
上載者:User

標籤:

自iphone4s以後,蘋果先後推出了iphone5、iphone5s、iphone6、iphone6plus、iphone6s、iphone6splus這些新的機型,它們的螢幕大小各有所異,從此給我們開發人員留下了一個蛋疼的問題:螢幕適配。

1、顯示座標定位方式:在4和4s的時代,我們採用顯示座標定位方式設定一個視圖的座標,比如view.frame  = CGRectMake(20, 70, 160, 160);在當時顯然是沒有任何問題的,因為手機螢幕的大小是固定的,屏寬320像素,屏高480像素。

2、autoresizingMask:自iphone5以後,手機螢幕的高度變成了568像素,有時候我們定義的視圖在iphone4和4s上運行起來位置擺放正常,但是在5和5s上就不那麼和諧了,這就對開發人員提出了適配的任務:如何讓視圖在不同大小的螢幕上恰到好處的展現出來呢?其實蘋果最先推出來的跟適配沾邊的技術autoresizingMask。autoresizingMask能給出子視圖相對於父親視圖的對齊與縮放係數,當父視圖發生變化時,通過每個視圖autoresizingMask即可自動得出新的位置。使用步驟是

第一步:設定父視圖的autoresizesSubviews屬性為YES,superView.autoresizesSubviews = YES;,否則後面的autoresizingMask都將失效。

第二步:設定子視圖的autoresizingMask, subView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin。

這裡面的autoresizingMask屬性是一個枚舉值,枚舉值各項含義如下:UIViewAutoresizingNone:就是不自動調整。

UIViewAutoresizingFlexibleLeftMargin: 自動調整與superView左邊的距離,保證與superView右邊的距離不變。

UIViewAutoresizingFlexibleRightMargin: 自動調整與superView的右邊距離,保證與superView左邊的距離不變。

UIViewAutoresizingFlexibleTopMargin: 自動調整與superView頂部的距離,保證與superView底部的距離不變。

UIViewAutoresizingFlexibleBottomMargin: 自動調整與superView底部的距離,也就是說,與superView頂部的距離不變。

UIViewAutoresizingFlexibleWidth: 自動調整自己的寬度,保證與superView左邊和右邊的距離不變。

UIViewAutoresizingFlexibleHeight: 自動調整自己的高度,保證與superView頂部和底部的距離不變。

UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin: 自動調整與superView左邊的距離,保證與左邊的距離和右邊的距離和原來距左邊和右邊的距離的比例不變。比如原來距離為20,30,調整後的距離應為68,102,即68/20=102/30。遺憾的是這些技術的缺陷也十分明顯,是一個不成熟的技術,原因有兩點:

(1)、autoresizingMask縮放比例是UIKit內部計算的,開發人員無法指定縮放比例的精確值。

(2)、變化規則只能基於父子視圖,無法解決兄弟視圖之間的位置關係。所以在iOS6推出自動布局(Auto Layout)技術後,autoresizingMask成為一項雞肋技術。可以用食之無味,棄之可惜來形容。

3、AutoLayout-可視化編程自動布局:關於AutoLayout技術有可視化編程和純程式碼兩種方式,本處先講解可視化的方式。自動布局是對autoresizingMask的進一步改進,它允許開發人員在介面上的任意兩個視圖之間建立精確的線性變化規則。所謂線性變化就是數學中的一次函數,即: y = m*x + c  其中x和y是介面中任意兩個視圖的某個布局屬性,m為比例係數,c為常量。在storyboard或者xib中設定約束的方案有三種:

(1)在設計器中長按Control鍵拖動控制項。

(2)在左側文檔結構視窗中長按Control鍵拖動控制項。

(3)點擊設計器底部表徵圖,pin設定距離約束、固定寬高約束、等高等寬和寬高比約束,align設定對齊約束。

注意:方案(1)和(2)中同時按住Shift鍵與Option鍵可以同時設定多個約束。前面我們提到了一個重要概念就是約束,約束有很多種類,現列出如下:Leading :距離另一視圖左邊距離的約束

Trailing :距離另一視圖左邊距離的約束

Top :距離另一視圖頂部距離的約束

Bottom :距離另一視圖底部距離的約束

Width:單個視圖固定寬度的約束

Height:單個視圖固定高度的約束

Equal Widths:兩個視圖等寬的約束

Equal Heights:兩個視圖等高的約束

Aspect Ratio:單個視圖固定寬高比的約束

Horizontally in Container:固定在父視圖水平方向中線的約束

Vertically in Container:固定在父視圖垂直方向中線的約束

Vertically in Container:固定在非父視圖水平方向中線的約束

Horizontall Centers:固定在非父視圖垂直方向中線的約束

Vertical Spacing:兩個視圖垂直方向距離的約束

Horizontally Spacing:兩個視圖水平方向距離的約束

align Top to:頂部對齊約束

align Bottom to:底部對齊約束

align Leading to:左邊對齊約束

align Trailing to:右邊對齊約束

還有一些選項幾乎是我們必用的,含義列出如下:Update Frames:更新座標以適應約束

Update Constraints:更新約束以適應座標

Add Constraints:添加約束

Constain to margins:如果你點了constrain to margins,左右會有8個點的空擋,從8個點後開始計算約束,而沒有點時,已螢幕的0點開始計算。建議取消勾選。

我們可以在畫布的右邊查看每個約束的詳情,我們在前面講的y相對於x發生變化的公式 y = m*x + c  在這裡得到了呼應,First Item對應公式中的y,表示因變數

Relation對應公式中的=,表示相等關係,這裡顯示的是Equal即相等

Second Item對應公式中的x,表示自變數

Multiplier對應公示中的m,表示縮放比例係數

Constant對應公示中的c,表示位移常量

點擊First Item或者Second Item下拉式功能表,選擇Reverse First And Second Item即可交換雙方的位置。

得反函數:x = 1/m * y - c/m

值得一提的是約束既不能少,少了不能確定視圖位置,也不能多,多了會衝突。

另外,某些用來展現內容的使用者控制項,例如文本控制項UILabel、按鈕UIButton、圖片視圖UIImageView等,它們具有自身內容尺寸(Intrinsic Content Size),此類使用者控制項會根據自身內容尺寸添加布局約束。也就是說,如果開發人員沒有顯式給出其寬度或者高度約束,則其自動添加的自身內容約束將會起作用。

4、AutoLayout-代碼自動布局:並非所有的情況都能用IB來解決,比如定義諸如某視圖的高度等於另一個視圖的寬度這樣的約束,通過代碼構建自動布局約束是最基礎的,也是最靈活的方式。缺點是代碼很冗長。每一個布局約束是一個NSLayoutConstraint執行個體,NSLayoutConstraint類的主要屬性定義如下

@property (readonly, assign) id firstItem;

@property (readonly) NSLayoutAttribute firstAttribute;

@property (readonly) NSLayoutRelation relation;

@property (readonly, assign) id secondItem;

@property (readonly) NSLayoutAttribute secondAttribute;

@property (readonly) CGFloat multiplier;

@property CGFloat constant;

...

+(instancetype)constraintWithItem:(id)firstItem attribute:(NSLayoutAttribute)firstAttribute

relatedBy:(NSLayoutRelation)relation

toItem:(id)secondItem attribute:(NSLayoutAttribute)secondAttribute

multiplier:(CGFloat)multiplier constant:(CGFloat)constant;

每一個布局約束就是一個明確的線性變化規則,在數學上是以一次函數的形式表示,即:

y = m * x + c

每個約束就對應如下關係:

firstItem.firstAttribute {==,<=,>=} secondItem.secondAttribute * multiplier + constant

我們可以調用NSLayoutConstraint類的constraintWithItem:…方法,傳入所有需要的參數構造一個新的約束。

(1)、firstItem與secondItem分別是介面中受約束的視圖與被參照的視圖,他們不一定非得是兄弟關係或者父子關係,只要是他們有著共同的祖先視圖即可。

(2)、firstAttribute與secondAttribute分別是firstItem與secondItem的某個布局屬性(NSLayoutAttribute),其中NSLayoutAttributeNotAnAttribute當我們需要為某個視圖精確指定一個寬度或者高度值時,這時候secondItem為nil,secondAttribute為    NSLayoutAttributeNotAnAttribute。

(3)、relation定義了布局關係

typedef NS_ENUM(NSInteger, NSLayoutRelation)

{

NSLayoutRelationLessThanOrEqual = -1,

NSLayoutRelationEqual = 0,

NSLayoutRelationGreaterThanOrEqual = 1,

};

布局關係可以是相等、大於等於或者小於等於。

(4)、multiplier即比例係數。

(5)、constant即常量

使用案例如下:

第一步:預設的autoresizingMask代碼和自動布局約束會衝突,設定為no,程式只有自動布局約束代碼,避免衝突。

logoView.translatesAutoresizingMaskIntoConstraints = NO;

第二步:設定約束,為了唯一確定視圖的位置,我添加了四個約束

logoViewtopConstraint = [NSLayoutConstraint constraintWithItem:logoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1.0f constant:80];

NSLayoutConstraint *logoViewcenterConstaint = [NSLayoutConstraint constraintWithItem:logoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0];

NSLayoutConstraint *logoViewwidthConstaint = [NSLayoutConstraint constraintWithItem:logoView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.3f constant:0];

NSLayoutConstraint *logoViewhightConstaint = [NSLayoutConstraint constraintWithItem:logoView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:logoView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0];

第三步:添加約束

logoViewtopConstraint.active  = YES;

logoViewcenterConstaint.active = YES;

logoViewwidthConstaint.active = YES;

logoViewhightConstaint.active = YES;

5、VFL:Visual Format Language,可視化格式語言,能直觀又簡單的建立約束,缺點是不能表達所有的約束。用法舉例:

第一步:autoresizingMask設定為NO。

logoView.translatesAutoresizingMaskIntoConstraints = NO;

第二步:使用VFL添加約束

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-80-[logoView]" options:NSLayoutFormatAlignAllLeft metrics:nil views:@{@"logoView":logoView}]];

文法是這樣的,H表示橫向

V表示豎向

| 表示父視圖

[視圖名字]表示視圖

-表示 間距

-間距- 表示設定其他間距

[視圖名字(設定視圖的寬高)]

上面constraintsWithVisualFormat方法的參數含義如下

VisualFormat:VFL語句

options:基於哪一個選項(基於哪個方向去計算布局)

metrics:綁定數值(NSNumber) 與字串

views:綁定視圖 與字串

NSDictionaryOfVariableBindings:是一個宏,方便我們構建字典,NSDictionaryOfVariableBindings(logoView)就等於@{@”logoView”: logoView}。

另外需要注意一些精簡寫法(1)、省略:也就是說如果間距為0則不用明確寫出,所以@”H:|-0-[logoView]-0-|”可以精簡為@”H:|[logoView]|”

(2)、合并:例如@"H:[password]-20-[tfPassword]"和@"[tfPassword]-40-|"可以合并為@"H:[password]-20-[tfPassword]-40-|"

6、Masonry:是第三方庫,讓自動布局的寫法更加簡便,是現在程式員使用較為普遍的一種方案。用法案例如下:

第一步:聲明為__weak,因為我們後面要使用block,以防記憶體問題。

__weak typeof(self) weakself = self;

第二步:添加約束。

[logoView mas_makeConstraints:^(MASConstraintMaker *make) {

make.centerX.equalTo(weakself.view);

make.top.mas_equalTo(80);

make.width.mas_equalTo(weakself.view.bounds.size.width*0.3);

make.height.mas_equalTo(weakself.view.bounds.size.width*0.3); }];

Masonry用法比較簡單,需要注意的地方主要有兩點

注意點(1): 使用 mas_makeConstraints方法的元素必須事先添加到父元素的中,例如[self.view addSubview:view];

注意點(2): masequalTo 和 equalTo 區別:masequalTo 比equalTo多了類型轉換操作,一般來說,大多數時候兩個方法都是 通用的,但是對於數值元素使用mas_equalTo。對於對象或是多個屬性的處理,使用equalTo。特別是多個屬性時,必須使用equalTo,例如 make.left.and.right.equalTo(self.view);

另外,在Masonry中,and,with都沒有具體操作,僅僅是為了提高程式的可讀性

7、SizeClass:在調適型配置中,蘋果提出了Size Class(尺寸類型)的概念,用於在概念上表示水平或垂直方向的大小。共有3種類型尺寸,大的稱之為Regular(標準尺寸類型,簡記為+),小的稱之為Compact(緊湊尺寸類型,簡記為-),任意的稱之為Any(Regular和Compact任意)。所有的iPad不管什麼方位都是[+, +]

所有的iPhone在豎屏時都是[-, +]

在橫屏時只有iPhone 6 Plus和6s Plus是[+, -],其餘的iPhone都是[-, -]。當設計人員給出了不同裝置上的介面設計稿之後,作為開發人員的我們應該首先總結出最通用的自動布局方案,將其作為任意尺寸類型的自動布局(基類);把差異化的布局放在某個特定尺寸類型的自動布局(子類)。使用的時候一定要確保Use Auto Layout複選框和Use Size Classes複選框都已選中

8、利用宏進行適配:我們觀察到從iphone5以後所有的蘋果機型,儘管螢幕大小不盡相同,但是螢幕的寬高比確是一致的,這就為我們進行適配又找到了一絲線索,實際上,我們可以利用寬高比相等這點,以某種機型為基礎,比如5s,在5s上的視圖,搬到iphone6以上時,就將這個視圖的大小進行等比擴大,同理,在4和4s上時,將這個視圖的大小進行等比縮小,這樣視圖在不同大小螢幕上,只是大小不一樣而已,看起來卻都是和諧的,因為視圖相對於螢幕大小的比例是一樣的 。用法案例:pch是一個通用檔案,在pch檔案匯入的標頭檔和宏,對全域類都是有效,我們在pch檔案裡定義兩個帶參數的宏,#define Width(x) [UIScreen mainScreen].bounds.size.width/320*x

#define Height(y) [UIScreen mainScreen].bounds.size.height/568*y,這樣我們在控制器中設定一個視圖的位置可以這麼寫,bigView = [[UIView alloc] initWithFrame:CGRectMake(Width(20), Height (70), Width(160), Height(160))];當然你可以重寫CGRectMake方法,這樣使用的時候會更加的方便,筆者將這個最後的小任務就交給大家思考下吧!

iOS自動適配

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.