1. 程式人生 > >iOS-setNeedsLayout等布局方法

iOS-setNeedsLayout等布局方法

this post mar mod 不為 ret clas 註意點 init

列舉下iOS layout的相關方法:

layoutSubviews
layoutIfNeeded
setNeedsLayout
setNeedsDisplay
drawRect
sizeThatFits
sizeToFit
大概經常使用的上面幾個 , 詳細的應該還有別的。

layoutSubviews
這種方法,默認沒有做不論什麽事情,須要子類進行重寫 。 系統在非常多時候會去調用這種方法:

1.初始化不會觸發layoutSubviews,可是假設設置了不為CGRectZero的frame的時候就會觸發。
2.addSubview會觸發layoutSubviews
3.設置view的Frame會觸發layoutSubviews。當然前提是frame的值設置前後發生了變化
4.滾動一個UIScrollView會觸發layoutSubviews
5.旋轉Screen會觸發父UIView上的layoutSubviews事件
6.改變一個UIView大小的時候也會觸發父UIView上的layoutSubviews事件

在蘋果的官方文檔中強調: You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.layoutSubviews, 當我們在某個類的內部調整子視圖位置時,須要調用。反過來的意思就是說:假設你想要在外部設置subviews的位置。就不要重寫。
setNeedsLayout
標記為須要又一次布局。不馬上刷新,但layoutSubviews一定會被調用
配合layoutIfNeeded馬上更新

layoutIfNeeded
假設,有須要刷新的標記,馬上調用layoutSubviews進行布局

這個動畫中實用到 舉個栗子 。

如圖 , 上面有個label ,中間有個button 。 label已經被自己主動布局到左上角 。

然後我們那個left的constraint

@IBOutlet weak var leftContrain:NSLayoutConstraint!
在viewDidLoad中聲明好。然後在Main.storyboard中進行連線。點擊button的時候 ,我們把左邊的距離改成100 。

在button的點擊事件裏加上這句。

leftContrain.constant = 100
然後我們想要一個動畫的效果。
假設這麽做

UIView.animateWithDuration(0.8, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.AllowAnimatedContent, animations: {
self.leftContrain.constant = 100
}, completion: nil)
你會發現然並卵 。事實上這句話self.leftContrain.constant = 100僅僅是運行了setNeedsLayout 標記了須要又一次布局。可是沒有馬上運行。所以我們須要在動畫中調用這種方法layoutIfNeeded
所以代碼應該這麽寫

leftContrain.constant = 100
UIView.animateWithDuration(0.8, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.AllowAnimatedContent, animations: {
self.view.layoutIfNeeded() //馬上實現布局
}, completion: nil)
所以上面無論寫多少約束的改變。僅僅須要在動畫裏動用 一次self.view.layoutIfNeeded() ,全部的都會已動畫的方式 。假設一些變化不想動畫 。在動畫前運行self.view.layoutIfNeeded()

drawRect
這種方法是用來重繪的。

drawRect在下面情況下會被調用:
1、假設在UIView初始化時沒有設置rect大小,將直接導致drawRect不被自己主動調用。

drawRect調用是在Controller->loadView, Controller->viewDidLoad 雙方法之後掉用的.所以不用操心在控制器中,這些View的drawRect就開始畫了.這樣能夠在控制器中設置一些值給View(假設這些View draw的時候須要用到某些變量值).
2、該方法在調用sizeToFit後被調用。所以能夠先調用sizeToFit計算出size。然後系統自己主動調用drawRect:方法。3、通過設置contentMode屬性值為UIViewContentModeRedraw。那麽將在每次設置或更改frame的時候自己主動調用drawRect:。4、直接調用setNeedsDisplay,或者setNeedsDisplayInRect:觸發drawRect:,可是有個前提條件是rect不能為0。以上1,2推薦。而3,4不提倡

drawRect方法使用註意點:
1、若使用UIView畫圖。僅僅能在drawRect:方法中獲取對應的contextRef並畫圖。

假設在其它方法中獲取將獲取到一個invalidate的ref而且不能用於畫圖。drawRect:方法不能手動顯示調用。必須通過調用setNeedsDisplay 或者 setNeedsDisplayInRect,讓系統自己主動調該方法。

2、若使用calayer畫圖,僅僅能在drawInContext: 中(相似於drawRect)繪制。或者在delegate中的對應方法繪制。相同也是調用setNeedDisplay等間接調用以上方法3、若要實時畫圖,不能使用gestureRecognizer,僅僅能使用touchbegan等方法來掉用setNeedsDisplay實時刷新屏幕

sizeToFit
sizeToFit會自己主動調用sizeThatFits方法;
sizeToFit不應該在子類中被重寫,應該重寫sizeThatFits
sizeThatFits傳入的參數是receiver當前的size,返回一個適合的size
sizeToFit能夠被手動直接調用sizeToFit和sizeThatFits方法都沒有遞歸。對subviews也不負責。僅僅負責自己

文/大石頭布(簡書作者)
原文鏈接:http://www.jianshu.com/p/eb2c4bb4e3f1

iOS-setNeedsLayout等布局方法