autoResizing autoLayout和sizeClass

autoResizing autoLayout和sizeClass


1. autoResizing

autoresizing是蘋果早期的ui布局適配的解決辦法,iOS6之前完全可以勝任了,因為蘋果手機只有3.5寸的屏幕,在加上手機app很少支持橫屏,所以iOS開發者基本不用怎么適配布局,所有的ui控件只要相對父控件布局就可以了,沒錯autoResizing就是一個相對于父控件的布局解決方法;注意:它只能相對父控件布局;


在xcode中可以通過可視化的界面調整也可以通過代碼去控制

Snip20141209_1.png

在用autoResizing的時候需要關閉autoLayout和sizeclass(如果是用xcode6)
他們之間是互相沖突的

可以通過圖片看到autoResizing通過可視化能調整的只有6根線剛好和它的6個枚舉值對應

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0, 
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

外邊的4根線用來設置當前view距離父控件的上、下、左、右的距離是否固定;
內部的兩根線來設置view是否跟隨父控件來自適應width和height;
代碼則可以通過view.autoresizingMask = ...來設定autoResizing值;
autoResizing的功能僅此而已;顯然不夠用;


舉例:
1:讓兩個等寬等高的view之間的間距永遠固定,如圖的紅色view和藍色view,想讓它們之間的距離固定通過autoResizing是不行的;因為autoResizing是相對父控件進行布局的,不可以在兩個兄弟view之間建立布局關系;

Snip20141209_3.png
Snip20141209_4.png

可以看到一個橫屏和豎屏就已經不能滿足需求了,更別說屏幕尺寸還要變大
當然你有可能通過其他復雜的輔助手段實現,但是很麻煩;因為不僅僅是橫豎屏幕;屏幕尺寸也要變了;
autoResizing就到此為止,顯然它已近過時,了解一下就可以了;


2. autoLayout iOS6之后

做蘋果開發的一個好處是有一個很好的東家,蘋果公司,他不僅很注重用戶體驗,而且還不忘為開發者去除一些不必要的麻煩(例如:ARC的出現...)
autoLayout:可以在任意兩個控件之間建立布局關系,可以是父子view也可以是兄弟view;功能強大了許多,當然學習成本也高了不少;
如圖:

Snip20141209_5.png

為了方便了解先勾選autoLayout就可以了,sizeclass先別勾了(如果是xcode6)
autoLayout的設置功能就上圖中下方的紅色方框中;


左起第一個:

Snip20141209_7.png

通過圖中紅色框圈住的地方可以看出來,該處功能是設置多個view之間的對齊方式,所以設置的時候要同時選中多個View進行設置

**第二個: **

Snip20141209_10.png

這一部分相當于是一個autoResizing,強大之處在于可以是任意兩個view的相對布局,可以設置距離父控件的上下左右位置(紅色框),還有自身的寬高,還可以相對其他控件設置寬高(藍色框)

第三個:

Snip20141209_11.png

這部分是用來添加、刪除、和更新約束的,上半部分是對于選中view的約束更新,下邊是容器中得所有view的約束

除了上邊,還可以通過control按鍵配合拖線來做autoLayout,如圖:

autoLayout脫線.gif

===
例子:用autolayout完成剛才autoResizing不能完成的任務,這里繼續加大難度,除了讓紅色view和藍色view等寬等高,而且距離始終保持不變以外,還要讓兩個view整體垂直居中于屏幕;先看最終的效果圖

Snip20141209_17.png

橫屏效果

Snip20141209_19.png

可以看到不管是橫屏豎屏還是大屏小屏,都是沒問題的,到中分線的距離固定且相等;


下邊開始一步一步通過autoLayout完成

第一步:

先讓兩個view等高等寬, 在xcode中同時選中紅色view和藍色view,勾選等寬,等高;

Snip20141209_12.png

這里也可以用另外一種方式:按住control進行拖線,為了可讀性和看著直觀就不用了;
這時請注意看xcode得左上角,會有紅色的箭頭出現,表示添加的約束不完整,先說明:約束的完整性,一個view在視圖中的位置相對固定(寬高和相對位置),那么約束就完整,注意是相對固定; 而這里我們只是讓兩個view等寬和等高,位置在哪里并沒有說明,約束當然不完整;所以有紅色的錯誤;

Snip20141209_14.png

知道紅色的報錯箭頭正常之后,我們繼續,添加的每一條約束都是一個實體,可以在view中看到,點擊每條約束可以在xcode的右側編輯欄中看到約束的線性公式,這個線性公式正是蘋果工程師的智慧結晶,巧妙的運用數學的智慧值得我們去學習和體會;

Snip20141209_15.png

順著這幾個文本框從上往下讀可以得到如下的線性公式(Priority優先級不算入公式):
view.width Equal view.width * 1 + 0
化解得:
view.width = view.width 就這樣實現了兩個view之間的width關系的描述,將這個公式轉化成代碼應該很easy吧.. 哈哈

說明:這里我們查看的是width約束,所以是view.width,兩個view可以分別認為是紅色view和藍色view,可以相互對調位置
也許上邊不倫不類的公式很難理解,那么假設紅色view的寬度為x, 藍色view的寬度為y,對于任意兩個實數x,y,都可以用下面的線性公式(或者說是一次線性函數)表示他們之間的關系:
y = k·x + b 其中k是系數(就是上圖中的Multipliter), b是常數(是上圖中的Constant);
就是這個小學已經學習過的一次函數,可以滿足任何兩個view的任何邊距關系;


第二步:
了解這些之后,回到正題,剛才只是添加了兩個view等寬等高,接下來,為了保證不會錯亂,我們可以一個一個的來完成約束,這里先固定紅色的view:
這里采用control拖線的方式:

redCenter.gif

這里我們讓紅色view和藍色的centerY到父view的centerY都是70,這樣操作后相當于兩個view在豎直方向上的位置固定;水平方向和每個view的快高具體是多少都還沒固定;所以xcode左上角繼續報紅色錯誤
第三步:
固定水平位置和寬高,這里固定寬高,只需要固定其中的一個即可,因為兩個view的寬高相同;

horiAndWG.gif

可以看到添加完后紅色的箭頭變成了黃色,這表示,約束完整只差一步update了,這是你可以通過點擊黃色箭頭update或者如圖:

update.gif

好了,到此就搞定了;這個看似只有兩個view,但是這個需求已經是相對復雜了;

案例二:
通過上邊的案例一可以看出autoLayout可以設置任意兩個view之間的約束,可以說能實現任何想要布局;
下邊的案例:讓四個view始終等分屏幕:
效果圖(為了說明效果,中間留了一個像素的間距):

等分屏幕.gif

思路:先固定好其中的一個,然后其他view和這個view等寬等高,然后設置相對父控件的約束;

代碼實現autolayout

每一條約束都是一個:NSLayoutConstraint對象

NSLayoutConstraint *layout = [NSLayoutConstraint constraintWithItem:(id) 
attribute:(NSLayoutAttribute) relatedBy:NSLayoutRelationEqual toItem:(id) 
attribute:(NSLayoutAttribute) multiplier:(CGFloat) constant:(CGFloat)];
[self.view addConstraint:layoutConstraint]

該方法正是剛才線性公式 y = k·x + b 的代碼表示;所以雖然很長,但是很容易讀懂;最后要記得把約束添加到view上,添加的時候必須要注意如果這個約束是父子view關系,約束必須加在父view上邊;
但是用代碼去實現autolayout實在是麻煩,剛才的兩個例子,每個例子中得約束有15個以上,如果用代碼實現,要創建15個以上的NSLayoutConstraint對象,還有弄清楚關系,不能寫錯;蘋果又為開發者考慮到了這一點;于是推出了為了寫autolayout方便的VFL語言;

VFL

嚴格來講不算語言,一中語法類似正則表達式的專門用來寫autolayout的;但是vfl并沒有帶來簡化,其繁瑣程度基本上是寫一行就不想寫第二行的程度:

NSString *vfl1 = @"|-hPadding-[_headerL]-hPadding-|";   
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1
options:0 metrics:metrics views:dict1]];   

和正則用法差不多,先用字符串寫一些匹配規則,然后就調用后邊的方法去解析這個規則到view上;我個人一直認為編程語言應該從簡,將復雜的東西屏蔽掉,使我們開發起來更高效,也有更多時間去處理好業務; 畢竟我們每天做的情就是讓用戶簡單起來,把復雜留給自己;所以vfl不用也罷;

一個label用autoLayout約束,會自動計算好寬高,并且上邊和下邊不會留空白;

Snip20141210_1.png

3. 蘋果界面設計的統一:sizeClass

<p>與其說科技的發展,拉近了空間中任意兩點的距離,讓交流、信息傳遞更加便捷;倒不如說由于交流和信息傳遞的需求更加迫切而推動了科技的進步;大屏顯然是一典型的例子,屏幕尺寸的相對增大,一定程度上方便了交流和信息傳遞,反之,相對小的屏幕對信息傳遞會有一定的局限;所以蘋果推出大屏幕的手機也是人類進步的需要,并不是什么跟風,扯淡結束;
屏幕大了,尺寸多了,帶給開發者的自然是適配方面的工作量和思考;正如大家知道的那樣;蘋果是一家最具追求的公司,他當然會推出可行的解決方案就是sizeClass;
sizeClass: 對屏幕尺寸進行了抽象:不在拘泥于具體尺寸;因為尺寸一直都在變化,我們如果按照尺寸去做適配,一定會很累的;</p>

sizeClass針對iOS設備的屏幕進行了抽象分類:

  1. compact (緊湊-小)
  2. Any (任意)
  3. Regular (寬松-大)

總結幾點:

  • sizeClass只是對屏幕進行了抽象分類;具體做屏幕的適配還得用autoLayout;
  • 沒有了橫豎屏的概念,也沒有了具體尺寸,不用在去談具體的iphone5還是ipad air;
  • 把高度和寬度都抽象為上邊的3種,3*3也就是總共9種類型;是9種類型,不是9種屏幕尺寸;

這樣做的結果就是你可以做好一個interface builder適配,然后不管在iphone還是ipad中都可以用了;
這就是蘋果的意愿;打開xcode如果新建一個universal項目,在xcode6之前會默認有兩個storyboard,一個是iphone的,一個是ipad版本的;xcode6之后只有一個,并且是正方形的,也就是說不管你做那種屏幕尺寸的app(無論是ipad還是iphone),都只用這一個storyboard就可以了;

了解3種抽象:

xcode中得樣子:

Snip20141210_2.png

具體來看:

20140915091835218.png

圖中9個格子代表 3*3的9中抽象;具體每種代表了那些含義可以選中看看;
比如iphone的豎屏它是這樣抽象的:compact width * regular height


通過sizeclass對屏幕進行分類,然后用autolayout去適配布局,可以說能實現任何想要的效果,并且不用區分設備而做不同的IB了,一個IB全部搞定,不管是iphone還是ipad;
案例:

有個view 100 * 100,在iphone豎屏時居于左上角,橫屏時在右下角,ipad中在正中間;

像這種過去看來變態的要求,在現在來說小菜一碟;

  • 步驟一:處理豎屏情況
    先用sizeclass固定屏幕為iphone豎屏:compact Width | Regular Height
Snip20141210_3.png

然后添加view到ib上,用autolayout固定尺寸100 * 100;并且在左上角;這里讓它居左20,居上20;

Snip20141210_5.png

然后update frame即可
后邊的同理解決,只不過要選對正確的sizeclass


iOS8加了sizeclass后,控件也多了個屬性,在storyboard上托個label出來(以label為例),選中,在右邊的菜單區域可以看到:installed,這個是用來控制改控件什么情況下顯示,當前什么都沒約束,表示Any * Any,就是不管是iphone什么尺寸還是ipad什么尺寸都可以顯示,點擊左邊的小加號+可以用sizeclass控制什么情況顯示;同樣的還有字體、圖片顯示;

Snip20141210_7.png

在不同的屏幕下顯示不同的字體:

Snip20141210_9.png

... 類似的功能還有很多
這個功能的思想和UIButton的三種狀態(normal, highlighted, selected)類似,只不過這里有9種狀態;


xcode6預覽

當屏幕種類變的越來越豐富的時候,如果要查看不同屏幕之間的適配情況,在過去是要不停的切換模擬器,然后運行看效果的,而切換模擬器是很耗時的一件事;xcode6之后,我們可以不用運行直接查看適配的情況;
對于剛才的事例進行如圖操作即可不運行查看適配效果;

預覽功能.gif

代碼預覽 @IBDesignable和@IBInspectable

這兩個屬性是xcode6新出的特性
如果不是通過IB創建view,而是通過代碼創建的View,如何在不運行程序的情況下實時的渲染在IB上呢,就是通過@IBDesignable和@IBInspectable;@IBDesignable告訴Interface Builder這個類可以實時渲染到界面中,但是這個類必須是UIView或者NSView的子類。通過@IBInspectable可以定義動態屬性,即可在attribute inspector面板中可視化修改屬性值。

示例(swift編寫): 這個例子自定義一個UIView的子類,該子類擁有一個UIButton

@IBDesignable
class MyCustomView: UIView {
  @IBInspectable var buttonTitleColor: UIColor! //  button title color
  @IBInspectable var buttonTitle: String!       //  button title
  @IBInspectable var buttonFrame: CGRect!       //  button frame
  var myButton: UIButton!
  
  override init(frame: CGRect) {
    // init stored properties
    buttonTitleColor = UIColor.redColor()
    buttonTitle = "我是按鈕"
    buttonFrame = CGRectMake(0, 0, 100, 50)
    
    myButton = UIButton(frame: buttonFrame)
    myButton.setTitleColor(buttonTitleColor, forState: .Normal)
    myButton.setTitle(buttonTitle, forState: .Normal)
    
    // call super initializer
    super.init(frame: frame)
    
    // add button to self
    addSubview(myButton)

  }
  required init(coder aDecoder: NSCoder) {
    // init stored properties
    buttonTitleColor = UIColor.redColor()
    buttonTitle = "button title"
    buttonFrame = CGRectMake(0, 0, 100, 50)
    
    myButton = UIButton(frame: buttonFrame)
    myButton.setTitleColor(buttonTitleColor, forState: .Normal)
    myButton.setTitle(buttonTitle, forState: .Normal)
    
    // call super initializer
    super.init(coder: aDecoder)
    
    // add button to self
    addSubview(myButton)
  }
  
  override func layoutSubviews() {
    // refresh button state through attribute inspector
    myButton.setTitleColor(buttonTitleColor, forState: .Normal)
    myButton.setTitle(buttonTitle, forState: .Normal)
  }
}

該類在界面上加了一個Button,并且添加了三個屬性,顏色、title、frame;這三個屬性都是用來描述button的,并且在前邊都加上@IBInspectable表示能夠在IB中實時預覽,不用運行程序啟動模擬器即可;
同時還重寫drawRect方法畫了一個矩形;
這個時候打開storyboard,添加一個View(為了控制gif圖的大小,圖中的View事先加好了約束,并且背景色改為藍色,方便識別);修改class為MyCustomView;預覽就會出現;同時我們將開始畫得矩形改為橢圓,然后再次查看storyBoard,預覽已經變為橢圓,真是太爽了,不用在浪費時間等待模擬器啟動去觀察UI的布局了;

inspectable預覽.gif

各種蘋果設備的尺寸和分別率

一圖勝千言

51530583gw1ek7mqv36zxj20go099jrm.jpg

QQ20141130-1@2x.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容