2013-03-19 49 views
15

因此,我在IB中設置了我的視圖設置,以便此文本標籤通過約束與縮略圖頂部對齊。將UILabel文本與約束垂直對齊並且沒有換行(自動佈局,單行)

enter image description here

但是我們知道,你不能垂直對齊在一個UILabel文本。我的文字根據內容的長度更新字體大小。全尺寸文字看起來不錯,而小文字在視圖上明顯較低。

enter image description here

existing solution涉及任一呼叫sizeToFit或更新的UILabel的幀匹配的文本的高度。不幸的是,後者(雖然很醜)的解決方案在你不應該更新幀的約束條件下效果不佳。前一種解決方案基本上不工作,當你需要文本autoshrink,直到它截斷。 (所以它不適用於有限數量的線路和自動收縮)。

現在至於爲什麼uilabel的固有尺寸(高度)不像寬度通過「Size to fit content」設置爲自然尺寸時所做的更新超出了我的想象。似乎絕對應該,但事實並非如此。

因此,我正在尋找替代解決方案。據我所知,您可能必須在標籤上設置高度限制,並在計算文本的高度後調整高度常數。任何人都有很好的解決方案

+0

@ hans-sjunnesson:你有沒有嘗試使用'None'的基線調整來自動縮小? – 2013-10-31 22:46:10

+0

@JörnEyrich雖然這將使文本堅持框架的頂部,UILabel的實際框架不會向上收縮。 這意味着如果您在其下面有一個子標籤,子標籤不會隨着標籤的縮小而向上追隨標籤。 – 2013-11-03 16:13:54

+0

退房http://stackoverflow.com/a/4942766/1039901 – 2013-11-04 12:14:04

回答

7

這個問題是一個真正的PITA解決。 API的這項工作在iOS7中不推薦使用,或者iOS7替代API被破壞也無濟於事。胡說!

您的解決方案很不錯,但它使用了不推薦使用的API(sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:),並且它的封裝不是很好 - 您需要將此代碼複製到任何想要此行爲的單元或視圖。好的一面是相當高效的!一個錯誤可能是當你進行計算時,標籤還沒有佈置,但是你根據寬度進行計算。

我建議你將這種行爲封裝在UILabel子類中。通過將大小計算放在覆蓋的intrinsicContentSize方法中,標籤將自動調整大小。我寫了下面,其中包含你的代碼,將在iOS6的執行和使用iOS7或非過時的API的好我的版本:

@implementation TSAutoHeightLabel 

- (CGSize) intrinsicContentSize 
{ 
    NSAssert(self.baselineAdjustment == UIBaselineAdjustmentAlignCenters, @"Please ensure you are using UIBaselineAdjustmentAlignCenters!"); 

    NSAssert(self.numberOfLines == 1, @"This is only for single-line labels!"); 

    CGSize intrinsicContentSize; 

    if ([self.text respondsToSelector: @selector(boundingRectWithSize:options:attributes:context:)]) 
    { 
     NSStringDrawingContext* context = [NSStringDrawingContext new]; 
     context.minimumScaleFactor = self.minimumScaleFactor; 

     CGSize inaccurateSize = [self.text boundingRectWithSize: CGSizeMake(self.bounds.size.width, CGFLOAT_MAX) 
                 options: NSStringDrawingUsesLineFragmentOrigin 
                attributes: @{ NSFontAttributeName : self.font } 
                 context: context].size; 

     CGSize accurateSize = [self.text sizeWithAttributes: @{ NSFontAttributeName : [UIFont fontWithName: self.font.fontName size: 12.0] } ]; 

     CGFloat accurateHeight = accurateSize.height * inaccurateSize.width/accurateSize.width; 

     intrinsicContentSize = CGSizeMake(inaccurateSize.width, accurateHeight); 
    } 
    else 
    { 
     CGFloat actualFontSize; 

#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 

     [self.text sizeWithFont: self.font 
        minFontSize: self.minimumFontSize 
       actualFontSize: &actualFontSize 
         forWidth: self.frame.size.width 
        lineBreakMode: NSLineBreakByTruncatingTail]; 

#pragma GCC diagnostic pop 

     CGRect lineBox = CTFontGetBoundingBox((__bridge CTFontRef)([UIFont fontWithName: self.font.fontName size: actualFontSize])); 

     intrinsicContentSize = lineBox.size; 
    } 

    return intrinsicContentSize; 
} 

@end 

這個實現是不完美的。我必須確保使用baselineAdjustment == UIBaselineAdjustmentAlignCenters,並且我不能100%確定地理解原因。我不喜歡我必須跳過才能獲得準確的文字高度。計算產生的結果與你的結果之間也有幾個像素差異。隨意玩它,並根據需要進行調整:)

boundingRectWithSize:options:attributes:context API似乎很破碎給我。雖然它(主要是!)正確地將文本限制爲輸入大​​小,但它不會計算正確的高度!它返回的高度取決於提供的字體的行高,即使縮放處於播放狀態。我的猜測是這是爲什麼UILabel默認情況下沒有這種行爲?我的解決方法是計算高度和寬度均準確的無約束大小,然後使用約束寬度和約束寬度之間的比率來計算約束大小的準確高度。什麼是PITA。在蘋果開發論壇中有很多投訴,在這裏指出這個API有這樣的問題。

+0

我覺得自己像一個問火星人,但什麼是PITA? – Kuzgun 2013-11-06 12:14:53

+1

疼痛在... 等等,火星人有屁股嗎? – 2013-11-06 13:35:51

+0

你得到賞金湯姆。儘管它可能感覺像是黑客,但實現屬於計算標籤的固有尺寸。 – 2013-11-06 13:37:30

-3

你在找什麼是這兩行代碼。

myLabel.numberOfLines = 0; 
myLabel.lineBreakMode = UILineBreakModeWordWrap; 

您還可以在屬性檢查器的「換行符」和「行」下找到它。

+0

如果您不希望它包裝,則不需要。 – 2013-03-19 21:38:06

2

所以我找到了一個解決方法。這有點冒險,但它有效。

所以我所做的是在我的IB文本行中添加高度約束,並在我的視圖中獲取對該文本的引用。

然後在layoutSubviews,更新我的約束高度基於字體的大小,我算算:

- (void)layoutSubviews { 
    if (self.titleLabel.text) { 
     CGFloat actualFontSize; 
     CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font minFontSize:9.0 actualFontSize:&actualFontSize forWidth:self.titleLabel.frame.size.width lineBreakMode:NSLineBreakByTruncatingTail]; 
     CGRect lineBox = CTFontGetBoundingBox((__bridge CTFontRef)([UIFont fontWithName:@"ProximaNova-Regular" size:actualFontSize])); 
     self.titleHeightConstraint.constant = lineBox.size.height; 
    } 
    [super layoutSubviews]; 
} 

起初我只是將它設置爲實際的字體大小,但即使一個調整(* 1.2)它仍然裁剪較小的字體大小。關鍵是使用CTFontGetBoundingBox,字體大小由我的計算確定。

這很不幸,我希望有更好的辦法。也許我應該轉向包裝。

1

TomSwift非常感謝您的回答,我真的很難處理這個問題。

如果有人仍然越來越怪異的行爲,我不得不改變:

intrinsicContentSize = CGSizeMake(inaccurateSize.width,accurateHeight);

intrinsicContentSize = CGSizeMake(inaccurateSize.width,accurateHeight * 2);

然後它像魅力一樣工作。