iOS 常用布局方式之Frame

級別: ★☆☆☆☆
標簽:「iOS布局」「iOS frame」「iOS frame bounds」
作者: Xs·H
審校: QiShare團隊

沐靈洛 線下分享iOS UIButton根據內容自動布局時,有和前端同學討論到iOS的常用布局方式。討論過程十分熱鬧,不容易記錄,但作者認為討論結果有必要記錄一下,希望能幫助到一些同學。
作者將iOS常用布局方式歸納為Frame、Autoresizing、Constraint、StackView和Masonry五種,并將逐一介紹。
本篇文章介紹Frame

frameUIView的屬性,用來描述UIView及其子類所表示的視圖的位置(origin)和大小(size)。frameiOS布局中最基本、最常用和最容易被開發者接受的布局方式。一般來說,可以通過以下方式很方便地創建并顯示一個視圖,如下。

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    _contentView = [[QiFrameContentView alloc] initWithFrame:self.view.bounds];
    _contentView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:_contentView];
}

在上述代碼中,作者在viewDidLoad中,將一個淺灰色的contentView添加到了self.view上,并將其frame設置為了self.view.bounds。顯然,作者希望淺灰色的contentView完全蓋住self.view(默認白色)。使用模擬器運行一下,初始效果如作者所愿,但將模擬器旋轉方向后,淺灰色的contentView沒有一起旋轉,在右側漏出了一部分白色的self.view,如下。

上述現象其實是frame特性的一種表現。在僅使用frame來布局視圖時,視圖的位置和大小是被唯一確定了的,不會跟隨父視圖的變化而變化,除非在某個時間點再次設置了frame。

作者希望contentView可以跟著self.view一起旋轉,始終保持完全覆蓋的效果,于是做了如下修改。

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    _contentView = [[QiFrameContentView alloc] initWithFrame:CGRectZero];
    _contentView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:_contentView];
}

- (void)viewWillLayoutSubviews {
    
    [super viewWillLayoutSubviews];
    
    _contentView.frame = self.view.bounds;
}

為實現想要的小伙,作者在viewWillLayoutSubviews方法中重新設置了contentViewframe,并將viewDidLoad中初始化contentView時設置的frame改為了CGRectZero因為在每一次self.view的frame變化后和self.view的子view發生變化前都會觸發viewWillLayoutSubviews方法。

借鑒上面的原理,作者在contentView上添加4subView,實現4等分的效果,如下圖。

實現上圖效果的代碼如下:

- (instancetype)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    
    if (self) {
    
        _subView1 = [[UIView alloc] initWithFrame:CGRectZero];
        _subView1.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.6];
        [self addSubview:_subView1];
        
        _subView2 = [[UIView alloc] initWithFrame:CGRectZero];
        _subView2.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:.6];
        [self addSubview:_subView2];
        
        _subView3 = [[UIView alloc] initWithFrame:CGRectZero];
        _subView3.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:.6];
        [self addSubview:_subView3];
        
        _subView4 = [[UIView alloc] initWithFrame:CGRectZero];
        _subView4.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:.6];
        [self addSubview:_subView4];
    }
    
    return self;
}

- (void)layoutSubviews {
 
    [super layoutSubviews];
    
    CGFloat margin = 20.0;
    CGFloat padding = 20.0;
    CGFloat width = (self.bounds.size.width - margin * 2 - padding) / 2;
    CGFloat height = (self.bounds.size.height - margin * 2 - padding) / 2;
    
    _subView1.frame = CGRectMake(margin, margin, width, height);
    _subView2.frame = CGRectMake(margin + width + padding, margin, width, height);
    _subView3.frame = CGRectMake(margin, margin + height + padding, width, height);
    _subView4.frame = CGRectMake(margin + width + padding, margin + height + padding, width, height);

    /*
    _subView4.qi_width = width;
    _subView4.qi_height = height;
    _subView4.qi_top = _subView3.qi_top;
    _subView4.qi_left = _subView3.qi_right + padding;
     */
}

其中,通過打點可知contentView中的layoutSubviews方法與viewController中的viewWillLayoutSubviews方法成對觸發,并且layoutSubviews晚于后者。

PS:bounds與frame有一定區別。
bounds只用來描述視圖的尺寸,就像一頁A4紙,不論把它放在桌子上還是地板上,它的bounds都不發生變化。
frame除了能夠描述視圖的尺寸外還能描述視圖的位置。再如A4紙,從桌子上挪到地板上,它的frame就發生變化了。

另外,為了更方便、直觀地使用frame布局視圖,可以使用類似上面代碼中注釋的代碼形式。具體的實現細節,可以在QiLayoutDemo中查看。


推薦文章:
iOS UIButton根據內容自動布局
iOS 指定初始化方法
UIView中的hitTest方法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容