概念
在UIView裡面有一個方法layoutSubviews:
複製代碼 代碼如下:
- (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.
layoutSubviews方法的具體作用
layoutSubviews是對subviews重新布局。比如,我們想更新子視圖的位置的時候,可以通過調用layoutSubviews方法,既可以實現對子視圖重新布局。
layoutSubviews預設是不做任何事情的,用到的時候,需要在自雷進行重寫。
執行個體
由於ipad的橫豎屏不同,所以好的應用,橫豎屏的頁面配置也不一樣。那麼就需要橫豎屏的整體解決方案。先看一個橫豎屏布局不一樣的介面。
下面兩張圖是來自同一個介面的橫豎版的截屏。可以看出,橫豎版顯示的內容相同,但是介面布局不同。要實現上述布局,主要是運用UIView中 layoutSubviews方法。當UIView設定為自動適配螢幕時,當使用者旋轉裝置的時候,會調用layoutSubviews方法,我們只需重寫 這個方法,然後判斷使用者螢幕的方向。在調整每個空間的位置即可。
下面是實現上述介面的最簡單的原型:
首先分析可以知道左面是圖片,右面是一個圖片加文字的視圖。下面就實現一個左面視圖右面是一個圖加一段字的案例。
案例的截圖如下
其中右面的文字和綠色部分是用一個子視圖封裝的。
整個布局是我在主視圖中添加了一個ContentView視圖,在ContentView視圖中添加了一個ArticleView視圖。
其中ArticleView和ContentView的xib檔案都開啟了
在ContentView中重寫layoutSubviews方法,然後根據stausbar的方向判斷當前視圖的橫豎屏。具體代碼:
複製代碼 代碼如下:
-(void)layoutSubviews{
[super layoutSubviews];
UIDeviceOrientation interfaceOrientation=[[UIApplication sharedApplication] statusBarOrientation];
if (interfaceOrientation == UIDeviceOrientationPortrait || interfaceOrientation == UIDeviceOrientationPortraitUpsideDown) {
//翻轉為豎屏時
[self setVerticalFrame];
}else if (interfaceOrientation==UIDeviceOrientationLandscapeLeft || interfaceOrientation == UIDeviceOrientationLandscapeRight) {
//翻轉為橫屏時
[self setHorizontalFrame];
}
}
-(void)setVerticalFrame
{
NSLog(@"豎屏");
[titleLable setFrame:CGRectMake(283, 0, 239, 83)];
[leftView setFrame:CGRectMake(38, 102, 384, 272)];
[rightView setFrame:CGRectMake(450, 102, 282, 198)];
}
-(void)setHorizontalFrame
{
NSLog(@"橫屏");
[titleLable setFrame:CGRectMake(183, 0, 239, 83)];
[leftView setFrame:CGRectMake(168, 122, 384, 272)];
[rightView setFrame:CGRectMake(650, 122, 282, 198)];
}
在具體的橫豎屏方法中,從新設定各個組件的座標即可。
接下來在ContentView中添加ArticleView視圖。
複製代碼 代碼如下:
-(id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder])) {
NSArray *arrayContentView =[[NSBundle mainBundle] loadNibNamed:@"ArticleView" owner:self options:nil];
rightView=[arrayContentView objectAtIndex:0];
[self addSubview:rightView];
}
return self;
}
由於我用的是xib,所以初始化方法為initWithCoder,在這個中添加新的視圖。
同樣在ArticleView中設定橫豎屏相應空間的座標即可。
複製代碼 代碼如下:
-(void)layoutSubviews{
[super layoutSubviews];
UIDeviceOrientation interfaceOrientation=[[UIApplication sharedApplication] statusBarOrientation];
CGRect rect=self.frame;
rect.size.width=282;
rect.size.height=198;
[self setFrame:rect];
if (interfaceOrientation == UIDeviceOrientationPortrait || interfaceOrientation == UIDeviceOrientationPortraitUpsideDown) {
//翻轉為豎屏時
[self setVerticalFrame];
}else if (interfaceOrientation==UIDeviceOrientationLandscapeLeft || interfaceOrientation == UIDeviceOrientationLandscapeRight) {
//翻轉為橫屏時
[self setHorizontalFrame];
}
}
-(void)setVerticalFrame
{
NSLog(@"豎屏");
[contentView setFrame:CGRectMake(12, 6, 250, 125)];
[textLable setFrame:CGRectMake(50, 139, 182, 39)];
}
-(void)setHorizontalFrame
{
NSLog(@"橫屏");
[contentView setFrame:CGRectMake(12, 6, 106, 158)];
[textLable setFrame:CGRectMake(135, 11, 147, 39)];
}
總結
layoutSubviews以下情況會被調用:
蘋果官方文檔已經強調,不能直接調用layoutSubviews對子視圖進行重新布局。那麼,layoutSubviews什麼情況下會被調用呢?通過百度搜尋,發現以下幾種情況layoutSubviews會被調用。
- 直接調用setLayoutSubviews。(這個在上面蘋果官方文檔裡有說明)
- addSubview的時候。
- 當view的frame發生改變的時候。
- 滑動UIScrollView的時候。
- 旋轉Screen會觸發父UIView上的layoutSubviews事件。
- 改變一個UIView大小的時候也會觸發父UIView上的layoutSubviews事件。
我簡單測試了一下,上面基本都會被調用。 注意:
當view的fram的值為0的時候,`addSubview`也不會調用`layoutSubviews`的。
layoutSubviews方法在對自雷視圖進行布局的時候非常方便。可以自己動手,深入理解layoutSubviews的調用機制。