autolayout height - UILabel sizeToFit不適用於自動佈局ios6




according text (12)

我該如何以編程方式(以及在哪種方法中)配置高度取決於文本的UILabel? 我一直試圖使用Storyboard和代碼的組合來設置它,但無濟於事。 大家在設置lineBreakModenumberOfLines推薦sizeToFit 。 但是,無論我將該代碼放在viewDidLoad:viewDidAppear:viewDidLayoutSubviews我都無法使其工作。 要么我把這個盒子放得太小,不能長長的文字,要么我把它做得太大,也不會縮小。


Answers

我碰到這個問題以及UIView子類,如果其內部元素包含一個UILabel作為一個。 即使使用自動佈局並嘗試所有推薦的解決方案,標籤也不會收緊文本的高度。 就我而言,我只希望標籤是一行。

無論如何,對我而言,工作是為UILabel添加所需的高度約束,並在調用intrinsicContentSize時手動將其設置為正確的高度。 如果你沒有包含在另一個UIView中的UILabel,你可以嘗試繼承UILabel並提供一個類似的實現,首先設置高度約束,然後返回
[super instrinsicContentSize]; 而不是[self.containerview intrinsiceContentSize]; 就像我在下面做的是特定於我的UIView子類。

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

在iOS 7和iOS 8上完美工作。


確保標籤的preferredMaxLayoutWidth的另一個選項與標籤的寬度保持同步:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end

在我的情況下,當使用UITableViewCell中的標籤時,標籤將會調整大小,但高度會超出表格單元高度。 這對我來說很有用。 我根據Max MacLeod做了,然後確定單元格高度設置為UITableViewAutomaticDimension。

你可以添加這個在你的init或awakeFromNib中,

self.tableView.rowHeight = UITableViewAutomaticDimension.  

在故事板中,選擇單元格,打開“大小”檢查器,並通過勾選“自定義”複選框確保將行高設置為“默認”。

8.0中有一個問題也需要在代碼中進行設置。


雖然這個問題以編程方式陳述,遇到同樣的問題,並且更喜歡在Interface Builder中工作,但我認為使用Interface Builder解決方案添加現有答案​​可能很有用。

首先是忘記sizeToFit 。 自動佈局將根據您的內容大小代表您處理此問題。

因此,問題是,如何通過自動佈局獲得標籤以適應其內容? 具體來說 - 因為這個問題提到它 - 高度。 請注意,相同的原則適用於寬度。

所以,讓我們從高度設置為41px的示例UILabel開始:

正如你在上面的屏幕截圖中看到的, "This is my text"在上面和下面都有填充。 這是UILabel的高度,它的內容,文本之間的填充。

如果我們在模擬器中運行應用程序,那麼我們看到同樣的事情:

現在,讓我們在界面生成器中選擇UILabel,並查看“大小”檢查器中的默認設置:

注意上面突出顯示的約束。 這是內容擁抱優先 。 正如Erica Sadun在優秀的iOS Auto Layout Demystified中描述的那樣 ,這是:

視圖傾向於避免對其核心內容進行額外填充

對於我們來說,使用UILabel,核心內容就是文字。

在這裡,我們來談談這個基本情景的核心。 我們給了我們的文本標籤兩個約束。 他們衝突。 有人說“高度必須等於41個像素高” 。 另一個說“擁抱視圖的內容,所以我們沒有任何額外的填充” 。 在我們的例子中,擁抱它的文本視圖,所以我們沒有任何額外的填充。

現在,使用Auto Layout,有兩個不同的指令說明做不同的事情,運行時必須選擇一個或另一個。 它不能做到這一點。 UILabel不能同時高41個像素, 並且沒有填充。

解決這個問題的方法是指定優先級。 一條指令必須比另一條指令具有更高的優先級。 如果兩個指令說不同的事情,並具有相同的優先級,則會發生異常。

所以讓我們一起去吧。 我的身高限制優先級為1000 ,這是必需的 。 內容擁抱高度是250 ,這是微弱的 。 如果我們將身高限制優先級降至249,會發生什麼情況?

現在我們可以看到神奇的開始發生。 讓我們試試sim:

真棒! 內容擁抱取得成功。 僅僅因為身高優先級249小於擁抱優先級250的內容。 基本上,我說“我在這裡指定的高度並不比我為內容擁抱指定的高度重要” 。 所以,內容擁抱贏了。

底線,讓標籤適合文本可以像指定高度或寬度約束一樣簡單,並正確設置與該軸的內容擁抱優先級約束關聯的優先級。

作為讀者的練習,會留下寬度的等效物!


請注意 ,在大多數情況下, Matt的解決方案按預期工作。 但如果它不適合你,請進一步閱讀。

要使標籤自動調整高度,您需要執行以下操作:

  1. 為標籤設置佈局約束
  2. 設置低優先級的高度限制。 它應該低於ContentCompressionResistancePriority
  3. 設置numberOfLines = 0
  4. 將ContentHuggingPriority設置為高於標籤的高度優先級
  5. 為標籤設置preferredMaxLayoutWidth。 該值由標籤用來計算其高度

例如:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_([email protected])]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

使用Interface Builder

  1. 設置四個約束。 高度限制是強制性的。

  2. 然後轉到標籤的屬性檢查器並將行數設置為0。

  3. 轉到標籤的大小檢查器,並增加垂直ContentHuggingPriority和垂直ContentCompressionResistancePriority。

  4. 選擇並編輯高度限制。

  5. 並降低身高限制優先。

請享用。 :)


在iOS 6中,如果使用自動佈局,如果UILabel的側面(或寬度)和頂部被固定,它將自動增長和縮小以適應其內容, 完全沒有代碼,也不會影響其抗壓性等等。 它很簡單。

在更複雜的情況下,只需設置標籤的preferredMaxLayoutWidth

無論哪種方式,正確的事情都會自動發生。


我覺得我應該貢獻一下,因為它花了我一段時間才找到正確的解決方案:

  • 我們的目標是讓Auto Layout在不調用sizeToFit()的情況下完成工作,我們將通過指定正確的約束來完成它:
  • 指定UILabel上的頂部,底部和前導/尾部空間約束
  • 將行數屬性設置為0
  • 內容擁抱優先級增加到1000
  • 將內容壓縮阻力優先級降低到500
  • 在您的底部容器約束上,將優先級降低到500

基本上,發生的事情是,你告訴你的UILabel,即使它有一個固定的高度約束,它可以使得為了擁抱內容而縮小它自身的約束(例如,如果你只有一行),但它不能打破約束使其更大。


UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));

我已經用xCode6解決了將“首選寬度”設置為自動並將標籤頂部,頂部和尾部固定


我以編程方式添加了UILabel ,在我的情況下,這足夠了:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0

在我的情況下,我創建了一個包含UILabel(未知長度)的UIView子類。 在iOS7中,代碼很簡單:設置約束,不必擔心內容擁抱或壓縮阻力,並且所有內容都按預期工作。

但在iOS6中,UILabel總是被剪裁成一行。 上面的答案都沒有為我工作。 內容擁抱和壓縮阻力設置被忽略。 防止裁剪的唯一解決方案是在標籤上包含preferredMaxLayoutWidth。 但我不知道如何設置首選寬度,因為其父視圖的大小未知(實際上,它將由內容定義)。

我終於在here找到了解決方案。 因為我正在處理自定義視圖,所以我可以在約束計算一次後添加以下方法來設置首選佈局寬度,然後重新計算它們:

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}

我正在更新我的應用程序,該應用程序僅基於支持iOS 4.3及更高版本的唯一標識符工作 所以,

1)我無法使用[UIDevice currentDevice].uniqueIdentifier; 因為它不再可用

2)我無法使用[UIDevice currentDevice].identifierForVendor.UUIDString因為它僅適用於iOS 6.0及更高版本,並且無法用於較低的iOS版本。

3)Mac地址不是一個選項,因為它在iOS-7中是不允許的

4) OpenUDIDOpenUDIDdeprecated ,並且在iOS-6上也存在問題。

5)廣告標識符也不適用於iOS-5及以下版本

最後這就是我所做的

a)將SFHFKeychainUtils添加到項目中

b)生成的CFUUID鍵字符串

 CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
    udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));

c)將它保存到Key Chain Utils中,否則它會生成一個新的Unique Time

最終代碼

+ (NSString *)GetDeviceID {
    NSString *udidString;
   udidString = [self objectForKey:@"deviceID"];
    if(!udidString)
    {
    CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
    udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
    CFRelease(cfuuid);
        [self setObject:udidString forKey:@"deviceID"];
    }
    return udidString;
}

+(void) setObject:(NSString*) object forKey:(NSString*) key
{
    NSString *objectString = object;
    NSError *error = nil;
    [SFHFKeychainUtils storeUsername:key
                         andPassword:objectString
                      forServiceName:@"LIB"
                      updateExisting:YES
                               error:&error];

    if(error)
        NSLog(@"%@", [error localizedDescription]);
}

+(NSString*) objectForKey:(NSString*) key
{
    NSError *error = nil;
    NSString *object = [SFHFKeychainUtils getPasswordForUsername:key
                                                  andServiceName:@"LIB"
                                                           error:&error];
    if(error)
        NSLog(@"%@", [error localizedDescription]);

    return object;
}

欲了解更多詳情





ios ios6 uilabel autolayout