===ios
autoresizing是蘋果早期的ui佈局適配的解決辦法,iOS6以前徹底能夠勝任了,由於蘋果手機只有3.5寸的屏幕,在加上手機app不多支持橫屏,因此iOS開發者基本不用怎麼適配佈局,全部的ui控件只要相對父控件佈局就能夠了,沒錯autoResizing就是一個相對於父控件的佈局解決方法;注意:它只能相對父控件佈局;
***
在xcode中能夠經過可視化的界面調整也能夠經過代碼去控制正則表達式
在用autoResizing的時候須要關閉autoLayout和sizeclass(若是是用xcode6)
他們之間是互相沖突的編程
能夠經過圖片看到autoResizing經過可視化能調整的只有6根線恰好和它的6個枚舉值對應swift
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之間創建佈局關係;xcode
能夠看到一個橫屏和豎屏就已經不能知足需求了,更別說屏幕尺寸還要變大
固然你有可能經過其餘複雜的輔助手段實現,可是很麻煩;由於不只僅是橫豎屏幕;屏幕尺寸也要變了;
autoResizing就到此爲止,顯然它已近過期,瞭解一下就能夠了;
***app
作蘋果開發的一個好處是有一個很好的東家,蘋果公司,他不只很注重用戶體驗,並且還不忘爲開發者去除一些沒必要要的麻煩(例如:ARC的出現...)
autoLayout:能夠在任意兩個控件之間創建佈局關係,能夠是父子view也能夠是兄弟view;功能強大了許多,固然學習成本也高了很多;
如圖:
爲了方便了解先勾選autoLayout就能夠了,sizeclass先別勾了(若是是xcode6)
autoLayout的設置功能就上圖中下方的紅色方框中;
***iphone
左起第一個:編程語言
經過圖中紅色框圈住的地方能夠看出來,該處功能是設置多個view之間的對齊方式,因此設置的時候要同時選中多個View進行設置ide
第二個: 函數
這一部分至關因而一個autoResizing,強大之處在於能夠是任意兩個view的相對佈局,能夠設置距離父控件的上下左右位置(紅色框),還有自身的寬高,還能夠相對其餘控件設置寬高(藍色框)
第三個:
這部分是用來添加、刪除、和更新約束的,上半部分是對於選中view的約束更新,下邊是容器中得全部view的約束
除了上邊,還能夠經過control按鍵配合拖線來作autoLayout,如圖:
===
例子:用autolayout完成剛纔autoResizing不能完成的任務,這裏繼續加大難度,除了讓紅色view和藍色view等寬等高,並且距離始終保持不變之外,還要讓兩個view總體垂直居中於屏幕;先看最終的效果圖
橫屏效果
能夠看到無論是橫屏豎屏仍是大屏小屏,都是沒問題的,到中分線的距離固定且相等;
***
下邊開始一步一步經過autoLayout完成
第一步:
先讓兩個view等高等寬, 在xcode中同時選中紅色view和藍色view,勾選等寬,等高;
這裏也能夠用另一種方式:按住control進行拖線,爲了可讀性和看着直觀就不用了;
這時請注意看xcode得左上角,會有紅色的箭頭出現,表示添加的約束不完整,先說明:約束的完整性,一個view在視圖中的位置相對固定(寬高和相對位置),那麼約束就完整,注意是相對固定
; 而這裏咱們只是讓兩個view等寬和等高,位置在哪裏並無說明,約束固然不完整;因此有紅色的錯誤;
知道紅色的報錯箭頭正常以後,咱們繼續,添加的每一條約束都是一個實體,能夠在view中看到,點擊每條約束能夠在xcode的右側編輯欄中看到約束的線性公式,這個線性公式正是蘋果工程師的智慧結晶,巧妙的運用數學的智慧值得咱們去學習和體會;
順着這幾個文本框從上往下讀能夠獲得以下的線性公式(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拖線的方式:
這裏咱們讓紅色view和藍色的centerY到父view的centerY都是70,這樣操做後至關於兩個view在豎直方向上的位置固定;水平方向和每一個view的快高具體是多少都還沒固定;因此xcode左上角繼續報紅色錯誤
第三步:
固定水平位置和寬高,這裏固定寬高,只須要固定其中的一個便可,由於兩個view的寬高相同;
能夠看到添加完後紅色的箭頭變成了黃色,這表示,約束完整隻差一步update了,這是你能夠經過點擊黃色箭頭update或者如圖:
好了,到此就搞定了;這個看似只有兩個view,可是這個需求已是相對複雜了;
案例二:
經過上邊的案例一能夠看出autoLayout能夠設置任意兩個view之間的約束,能夠說能實現任何想要佈局;
下邊的案例:讓四個view始終等分屏幕:
效果圖(爲了說明效果,中間留了一個像素的間距):
思路:先固定好其中的一個,而後其餘view和這個view等寬等高,而後設置相對父控件的約束;
每一條約束都是一個: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語言;
嚴格來說不算語言,一中語法相似正則表達式的專門用來寫autolayout的;可是vfl並無帶來簡化,其繁瑣程度基本上是寫一行就不想寫第二行的程度:
NSString *vfl1 = @"|-hPadding-[_headerL]-hPadding-|"; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:0 metrics:metrics views:dict1]];
和正則用法差很少,先用字符串寫一些匹配規則,而後就調用後邊的方法去解析這個規則到view上;我我的一直認爲編程語言應該從簡,將複雜的東西屏蔽掉,使咱們開發起來更高效,也有更多時間去處理好業務; 畢竟咱們天天作的情就是讓用戶簡單起來,把複雜留給本身;因此vfl不用也罷;
與其說科技的發展,拉近了空間中任意兩點的距離,讓交流、信息傳遞更加便捷;倒不如說因爲交流和信息傳遞的需求更加迫切而推進了科技的進步;大屏顯然是一典型的例子,屏幕尺寸的相對增大,必定程度上方便了交流和信息傳遞,反之,相對小的屏幕對信息傳遞會有必定的侷限;因此蘋果推出大屏幕的手機也是人類進步的須要,並非什麼跟風,扯淡結束;
屏幕大了,尺寸多了,帶給開發者的天然是適配方面的工做量和思考;正如你們知道的那樣;蘋果是一家最具追求的公司,他固然會推出可行的解決方案就是sizeClass;
sizeClass: 對屏幕尺寸進行了抽象:不在拘泥於具體尺寸;由於尺寸一直都在變化,咱們若是按照尺寸去作適配,必定會很累的;
sizeClass針對iOS設備的屏幕進行了抽象分類:
- compact (緊湊-小)
- Any (任意)
- Regular (寬鬆-大)
總結幾點:
把高度和寬度都抽象爲上邊的3種,3*3也就是總共9種類型;是9種類型,不是9種屏幕尺寸;
這樣作的結果就是你能夠作好一個interface builder適配,而後無論在iphone仍是ipad中均可以用了;
這就是蘋果的意願;打開xcode若是新建一個universal項目,在xcode6以前會默認有兩個storyboard,一個是iphone的,一個是ipad版本的;xcode6以後只有一個,而且是正方形的,也就是說無論你作那種屏幕尺寸的app(不管是ipad仍是iphone),都只用這一個storyboard就能夠了;
xcode中得樣子:
***
具體來看:
圖中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
而後添加view到ib上,用autolayout固定尺寸100 * 100;而且在左上角;這裏讓它居左20,居上20;
而後update frame便可
後邊的同理解決,只不過要選對正確的sizeclass
***
iOS8加了sizeclass後,控件也多了個屬性,在storyboard上託個label出來(以label爲例),選中,在右邊的菜單區域能夠看到:installed,這個是用來控制改控件什麼狀況下顯示,當前什麼都沒約束,表示Any * Any,就是無論是iphone什麼尺寸仍是ipad什麼尺寸均可以顯示,點擊左邊的小加號+
能夠用sizeclass控制什麼狀況顯示;一樣的還有字體、圖片顯示;
在不一樣的屏幕下顯示不一樣的字體:
... 相似的功能還有不少
這個功能的思想和UIButton的三種狀態(normal, highlighted, selected)相似,只不過這裏有9種狀態;
***
當屏幕種類變的愈來愈豐富的時候,若是要查看不一樣屏幕之間的適配狀況,在過去是要不停的切換模擬器,而後運行看效果的,而切換模擬器是很耗時的一件事;xcode6以後,咱們能夠不用運行直接查看適配的狀況;
對於剛纔的事例進行如圖操做便可不運行查看適配效果;
這兩個屬性是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的佈局了;
一圖勝千言
***