sizeThatFits 和 sizeToFit的區別

大兵布萊恩特0409發表於2018-07-12

程式碼部分 : https://github.com/ZhaoBingDong/CAAnimaiton

一 sizeThatFits 和 sizeToFit的區別

UIView 有個 sizeToFit 方法來計算 UIView 合適的 bounds.size, 注意 autolayout 約束過的 view 該方法失效.

- (void)sizeToFit;           
// calls sizeThatFits: with current view bounds and changes bounds size.
呼叫這個方法會改變當前 view 的 bounds.size 

複製程式碼
- (CGSize)sizeThatFits:(CGSize)size;     // return 'best' size to fit given size. does not actually resize view. Default is return existing view size
// 意思大概是 返回“最佳”大小適合給定的大小 預設返回已經存在的檢視 size
複製程式碼

當一個 view 例如 label 設定完 text 屬性後 呼叫[label sizeToFit]; 會根據 label 內容計算出合適的 size 來完全顯示 label 內容

    UILabel *label1          = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 100.0f, 0.0f, 0.0f)];
    label1.backgroundColor   = [UIColor yellowColor];
    label1.text              = @"當一個 view 例如 label 設定完 text 屬性後 呼叫[label sizeToFit]; 會根據 label 內容計算出合適的 size 來完全顯示 label 內容";
    label1.numberOfLines     = 0;
    [label1 sizeToFit];
    
    [self.view addSubview:label1];



複製程式碼

QQ20170303-171818@2x.png

上邊的方法 如果不設定 label 的 frame.size.with 那麼 label 會自適應寬度 而不會改變它的高度,所以 label 雖然設定了 numberOfLines = 0 ,依然無法換行 .大部分應用當文字一行顯示不完全時需要給 label 換行,那麼就要限定 label 的 maxWidth

還是同樣的程式碼 由於我指定了 label 的 width = 100.0f ,在 [label sizeToFit] 會發現 label 的最大 with =100 顯示不完全部分換行 高度自適應.

QQ20170303-172230.png

所以 sizeToFit 並不能夠完全按我們設想的哪樣去自適應 label 的 bounds.size

那麼 sizeToFit 內部到底做了哪些操作呢?

其實當呼叫 UIView 的 sizeToFit 後 會呼叫 sizeThatFits 方法來計算 UIView 的 bounds.size 然後改變 frame.size

 UIView 的 - (CGSize)sizeThatFits:(CGSize)size {
    
    CGSize newSize = [super sizeThatFits:size];
    NSLog(@"size =%@",NSStringFromCGSize(newSize));
    
    return newSize;
    
}
不妨將上邊程式碼部分發 UILabel 改成子類化的 MyLabel 重寫sizeThatFits 列印出  newSize ={99, 223.5}

複製程式碼

其實我們也可以不使用 [ label sizeToFit] 來計算 label 內容的 size ,首先呼叫 sizeThatFits 方法或者一個 CGSize 然後改變 label.frame.size 就可以得到 [label sizeToFit]一樣的效果

    // 或者給一個限定的寬度和高度 讓 label 在這個範圍內進行自適應 size
    CGSize labelSize = [label1 sizeThatFits:CGSizeMake([[UIScreen mainScreen] bounds].size.width, MAXFLOAT)];
    CGRect rect      = CGRectMake(label1.frame.origin.x, label1.frame.origin.y, labelSize.width, labelSize.height);
    [label1 setFrame:rect];

複製程式碼

QQ20170303-174116.png

由此可見 sizeThatFits 比 sizeToFit 更加靈活的設定一個自適應size 的 view , 可以定製 label 計算內部內容的規則

下邊是重寫子類 sizeThatFits 自定義的一個 計算label siztToFit 後改變 frame.size 的方法

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    _label1.frame = CGRectMake(_margin, _margin, _cacheSize1.width, _cacheSize1.height);
    _label2.frame = CGRectMake(_margin, CGRectGetMaxY(_label1.frame) + _margin, _cacheSize2.width, _cacheSize2.height);
}

- (CGSize)sizeThatFits:(CGSize)size
{
    CGFloat w = size.width;
    w -= 2 * _margin;
    
    _cacheSize1 = [_label1 sizeThatFits:CGSizeMake(w, MAXFLOAT)];
    _cacheSize2 = [_label2 sizeThatFits:CGSizeMake(w, MAXFLOAT)];
    CGFloat h = 3 * _margin + _cacheSize1.height + _cacheSize2.height;
    
    return CGSizeMake(size.width, h);
}

複製程式碼

當你呼叫 自定義 View 的 sizeToFit 方法後 會根據自定義的 sizeThatFits:(CGSize)size 規則來計算 label 來改變 label 完全內容的 size

    TestSizeFit *customerView = [[TestSizeFit alloc] init];
    [customerView setLabel1Text:@"大兵布萊恩特" setLabel2Text:@"巴爺科技 (上海) 有限公司"];
    
    [customerView sizeToFit];
    
    [self.view addSubview:customerView];

複製程式碼

通過上邊的程式碼示例 可以知道 sizeToFit 方法背後怎麼實現的 , sizeThatFits 可以子類化重寫自己的計算規則

QQ20170303-175215.png

好了,我是大兵布萊恩特,歡迎加入博主技術交流群,iOS 開發交流群

QQ20180712-0.png

相關文章