在Main.storyboard拖入一個UIView,隨便設置一個背景色,app
使用autolayout 爲紫色的view添加約束 :(0,0,100,100) ,iphone
爲該view添加動畫代碼以下:異步
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet NSLayoutConstraint *blueViewTop; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *blueViewLeading; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ self.blueViewTop.constant += 80; self.blueViewLeading.constant += 80; [UIView animateWithDuration:4 animations:^{ //[self.view layoutIfNeeded]; }]; }
這種方式下並無動畫效果.由於約束並非直接影響圖形的位置,設置完畢後系統會根據約束來計算圖形的位置和大小ide
因此當若是想修改約束實現動畫效果的話,須要在動畫代碼外邊調整約束,在動畫代碼內部調用layoutIfNeeded方法,該方法表示按照約束從新佈局界面 ;即增長[self.view layoutIfNeeded];oop
有時,在寫程序時,例如:佈局
在tableView的使用時,先設定一個heightForHeader的高度,再自定義一個HeaderView來顯示自行定義內容時,咱們須要重寫initWithReuseIdentifier方法;動畫
//設定heightForHeader的高度atom
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{spa
return 50;3d
}
當實例化一個HeaderView: [HeaderViewalloc]initWithReuseIdentifier:kIndentifer];
在重寫自定義的HeaderView的方法initWithReuseIdentifier時,設置自定義HeaderView內部數據時,咱們須要先調用才能實現對內部數據的設置
#pragma mark -
#pragma mark - layoutSubviews
-(void)layoutSubviews{
[superlayoutSubviews];
_headerButton.frame =self.contentView.frame;
[selfsetupUIDate];
}
那麼,咱們的UIView到底是怎麼 ,什麼時候纔對其子view進行佈局的呢,佈局的機制又是什麼?
iOS layout機制相關的這幾個方法:
- (CGSize)sizeThatFits:(CGSize)size
- (void)sizeToFit
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
- (void)layoutSubviews; // override point. called by layoutIfNeeded automatically. As of iOS 6.0, when constraints-based layout is used the base implementation applies the constraints-based layout, otherwise it does nothing.
- (void)setNeedsDisplay
- (void)drawRect
首先須要明白layoutSubviews在如下狀況下會被調用:
一、init初始化不會觸發layoutSubviews。
二、addSubview會觸發layoutSubviews。
三、設置view的Frame會觸發layoutSubviews,固然前提是frame的值設置先後發生了變化。
四、滾動一個UIScrollView會觸發layoutSubviews。
五、旋轉Screen會觸發父UIView上的layoutSubviews事件。
六、改變一個UIView大小的時候也會觸發父UIView上的layoutSubviews事件。
七、直接調用setLayoutSubviews。
八、直接調用setNeedsLayout。
也就是說layoutSubviews, 當咱們在某個類的內部調整子視圖位置時,須要調用
在使用時,須要需注意:
-layoutSubviews方法:這個方法,默認沒有作任何事情,須要子類進行重寫
-setNeedsLayout方法: 標記爲須要從新佈局,異步調用layoutIfNeeded刷新佈局,不當即刷新,但layoutSubviews必定會被調用
-layoutIfNeeded方法:若是,有須要刷新的標記,當即調用layoutSubviews進行佈局(若是沒有標記,不會調用layoutSubviews)
若是要當即刷新,要先調用[view setNeedsLayout],把標記設爲須要佈局,而後立刻調用[view layoutIfNeeded],實現佈局
其次drawRect在如下狀況下會被調用:
一、若是在UIView初始化時沒有設置rect大小,將直接致使drawRect不被自動調用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法以後掉用的.因此不用擔憂在 控制器中,這些View的drawRect就開始畫了.這樣能夠在控制器中設置一些值給View(若是這些View draw的時候須要用到某些變量 值).
二、該方法在調用sizeToFit後被調用,因此能夠先調用sizeToFit計算出size。而後系統自動調用drawRect:方法。
sizeToFit會自動調用sizeThatFits方法;
sizeToFit不該該在子類中被重寫,應該重寫sizeThatFits
sizeThatFits傳入的參數是receiver當前的size,返回一個適合的size
sizeToFit能夠被手動直接調用
sizeToFit和sizeThatFits方法都沒有遞歸,對subviews也不負責,只負責本身
三、經過設置contentMode屬性值爲UIViewContentModeRedraw。那麼將在每次設置或更改frame的時候自動調用drawRect:。
四、直接調用setNeedsDisplay,或者setNeedsDisplayInRect:觸發drawRect:,可是有個前提條件是rect不能爲0。
-setNeedsDisplay方法:標記爲須要重繪,異步調用drawRect
-setNeedsDisplayInRect:(CGRect)invalidRect方法:標記爲須要局部重繪
須要注意的是:
drawRect方法使用注意點:
一、 若使用UIView繪圖,只能在drawRect:方法中獲取相應的contextRef並繪圖。若是在其餘方法中獲取將獲取到一個invalidate 的ref而且不能用於畫圖。drawRect:方法不能手動顯示調用,必須經過調用setNeedsDisplay 或 者 setNeedsDisplayInRect,讓系統自動調該方法。
二、若使用calayer繪圖,只能在drawInContext: 中(相似魚drawRect)繪製,或者在delegate中的相應方法繪製。一樣也是調用setNeedDisplay等間接調用以上方法
三、若要實時畫圖,不能使用gestureRecognizer,只能使用touchbegan等方法來掉用setNeedsDisplay實時刷新屏幕
layoutSubviews對subviews從新佈局
layoutSubviews方法調用先於drawRect
setNeedsLayout在receiver標上一個須要被從新佈局的標記,在系統runloop的下一個週期自動調用layoutSubviews
layoutIfNeeded方法如其名,UIKit會判斷該receiver是否須要layout.根據Apple官方文檔,layoutIfNeeded方法應該是這樣的
layoutIfNeeded遍歷的不是superview鏈,應該是subviews鏈
drawRect是對receiver的重繪,能得到context
setNeedDisplay在receiver標上一個須要被從新繪圖的標記,在下一個draw週期自動重繪,iphone device的刷新頻率是60hz,也就是1/60秒後重繪