UILabel sizeToFit가 자동 레이아웃 ios6에서 작동하지 않습니다


152

높이가 텍스트에 의존하는 UILabel을 프로그래밍 방식으로 (어떤 방법으로) 구성해야합니까? 스토리 보드와 코드의 조합을 사용하여 설정하려고했지만 아무 소용이 없습니다. 모두가 권장 sizeToFit설정하는 동안 lineBreakModenumberOfLines. 그러나, 아무리 내가에 그 코드를 삽입하는 경우 viewDidLoad:, viewDidAppear:또는 viewDidLayoutSubviews나는 일에 그것을 얻을 수 없습니다. 긴 텍스트를 위해 상자를 너무 작게 만들면 크기가 커지거나 너무 커지거나 줄어들지 않습니다.


동일한 코드를 FWIW : label.sizeToFit()Xcode / viewController에서 사용할 필요가 없었으므로 제약 조건이 충분했습니다. Playground 에서 라벨을 만들지 않았습니다 . 지금까지 놀이터에서 작동하는 것으로 확인 된 유일한 방법은 수행하는 것입니다.label.sizeToFit()
Honey

답변:


407

주의 대부분의 경우에 것을 매트의 솔루션 작품은 예상대로. 그러나 그것이 효과가 없다면, 더 읽어보십시오.

라벨의 높이를 자동으로 조정하려면 다음을 수행해야합니다.

  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_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

인터페이스 빌더 사용

  1. 네 가지 제약 조건을 설정하십시오. 높이 제한은 필수입니다. 여기에 이미지 설명을 입력하십시오

  2. 그런 다음 레이블의 속성 관리자로 이동하여 줄 수를 0으로 설정하십시오. 여기에 이미지 설명을 입력하십시오

  3. 레이블 크기 관리자로 이동하여 세로 ContentHuggingPriority 및 세로 ContentCompressionResistancePriority를 ​​늘리십시오.
    여기에 이미지 설명을 입력하십시오

  4. 높이 구속 조건을 선택하고 편집하십시오.
    여기에 이미지 설명을 입력하십시오

  5. 높이 제약 우선 순위를 줄입니다.
    여기에 이미지 설명을 입력하십시오

즐겨. :)


4
예! 이것은 내가 찾던 정답입니다. 내가해야 할 유일한 것은 contentHuggingPriority 및 contentCompressionResistancePriority를 ​​필수로 설정하는 것입니다. IB에서 모든 것을 할 수 있습니다! 정말 고맙습니다.
circuitlego

43
당신은 이것을 지나치게 생각하고 있습니다. preferredMaxLayoutWidth레이블의 너비 (또는 오른쪽 및 왼쪽)를 설정 하거나 고정하십시오. 그게 다야! 그런 다음 내용에 맞게 자동으로 세로로 늘어나거나 줄어 듭니다.
matt

preferredMaxLayoutWidth 속성을 설정하고 레이블 너비를 고정해야했습니다. 매력처럼 작동 :)
MartinMoizard

preferredMaxLayoutWidth 및 / 또는 왼쪽과 오른쪽을 고정하는 것은 절대적이지 않습니다. 콘텐츠 포옹 및 압축 우선 순위는 우선 순위가 나머지 제약 조건보다 높으면 항상 작동합니다.
Eric Alford

2
^ 그리고 마지막으로 이유를 알 수 있습니다. 셀을 뷰의 맨 아래에 고정시킬 때 "to-to-bottom"제약 조건의 우선 순위를 1000보다 작게 설정해야합니다. 모든 것이 완벽하게 작동합니다. 보기가 축소 된 것 같습니다.
Mathijs Segers

65

iOS 6에서 자동 레이아웃을 사용하면 UILabel의 측면 (또는 너비)과 상단이 고정되어 있으면 코드가 전혀 없고 압축 저항 등이 지저분 하지 않고 내용에 맞게 수직 으로 자동으로 늘어나거나 줄어 듭니다 . 간단하다.

더 복잡한 경우에는 레이블을 설정하십시오 preferredMaxLayoutWidth.

어느 쪽이든, 올바른 일은 자동으로 발생합니다.


12
또한 numberOfLines를 0으로 설정해야합니다. 그렇지 않으면 줄 바꿈되지 않습니다.
devongovett

2
이것은 충분하지 않았습니다. @Mark의 답변에서 2 포인트가 필요했습니다.
Danyal Aytekin

코드를 작성하지 않고 여러 줄에서 자동으로 레이블을 확장 할 수 있습니까?
Noor

이것은 허용되는 답변보다 훨씬 덜 복잡합니다. 이 답변을 보여주는 두 가지 예 ( herehere )를 만들었습니다 .
Suragch

@Suragch 제약 조건을 사용하면 작동합니다. 그러나 Playground 의 동일한 코드 에서는 작동하지 않습니다 . 운동장에서label.sizeToFit()
Honey

42

질문에 프로그래밍 방식으로 설명되어 있지만 동일한 문제가 발생했으며 Interface Builder에서 작업하는 것을 선호하지만 Interface Builder 솔루션으로 기존 답변에 추가하는 것이 유용 할 수 있다고 생각했습니다.

첫번째는 잊어 버리는 것입니다 sizeToFit. 자동 레이아웃은 본질적인 콘텐츠 크기에 따라 사용자를 대신하여이를 처리합니다.

문제는 자동 레이아웃으로 콘텐츠에 맞게 레이블을 얻는 방법입니다. 구체적으로-질문에 언급되어 있기 때문에-높이. 너비에도 동일한 원칙이 적용됩니다.

높이가 41px로 설정된 UILabel 예제로 시작해 보겠습니다.

여기에 이미지 설명을 입력하십시오

위의 화면에서 볼 수 있듯이 "This is my text"위와 아래에 패딩이 있습니다. 그것은 UILabel의 높이와 내용, 텍스트 사이에 채워집니다.

시뮬레이터에서 앱을 실행하면 똑같은 것을 볼 수 있습니다.

여기에 이미지 설명을 입력하십시오

이제 Interface Builder에서 UILabel을 선택하고 크기 관리자에서 기본 설정을 살펴 보겠습니다.

여기에 이미지 설명을 입력하십시오

위의 강조 표시된 제약 조건에 유의하십시오. 그것이 콘텐츠 포옹 우선 순위 입니다. Erica Sadun은 훌륭한 iOS 자동 레이아웃 Demystified 에서 설명했듯이 다음과 같습니다.

뷰가 핵심 콘텐츠 주위에 추가 패딩을 피하기를 선호하는 방식

우리에게 UILabel의 핵심 내용은 텍스트입니다.

여기서 우리는이 기본 시나리오의 핵심에옵니다. 우리는 텍스트 레이블에 두 가지 제약 조건을 부여했습니다. 충돌합니다. "높이는 41 픽셀 높이와 같아야합니다" 라고 말합니다 . 다른 사람은 "여기에 뷰를 숨겨서 추가 패딩이 없도록한다"고 말합니다 . 이 경우 뷰를 텍스트 로 포옹하여 추가 패딩이 없도록하십시오.

이제 자동 레이아웃을 사용하면 서로 다른 작업을 수행하는 두 가지 명령으로 런타임에서 하나를 선택해야합니다. 둘 다 할 수는 없습니다. UILabel의 모두 41 픽셀 높이 될 수 패딩이 없다.

이를 해결하는 방법은 우선 순위를 지정하는 것입니다. 한 명령은 다른 명령보다 우선 순위가 높아야합니다. 두 명령어가 다른 말을하고 동일한 우선 순위를 가지면 예외가 발생합니다.

자 이제 가자. 내 높이 제약 조건의 우선 순위가 1000 되고, 필요를 . 콘텐츠 포옹 높이는 250 이며 합니다. 높이 제한 우선 순위를 249로 줄이면 어떻게됩니까 ?

여기에 이미지 설명을 입력하십시오

이제 우리는 마법의 시작을 볼 수 있습니다. 시뮬레이션을 해보자 :

여기에 이미지 설명을 입력하십시오

대박! 콘텐츠 포옹이 달성되었습니다. 높이 우선 순위 ( 249) 가 콘텐츠 포옹 우선 순위 ( 250) 보다 작기 때문에 만 . 기본적으로 나는 "여기에 지정하는 높이가 콘텐츠 포옹에 지정한 높이보다 덜 중요합니다"라고 말합니다 . 따라서 콘텐츠 포옹이 승리합니다.

결론은 텍스트에 맞게 레이블을 얻는 것이 높이 또는 너비 제약 조건을 지정하는 것만 큼 간단하고 해당 축의 내용 포옹 우선 순위 제약 조건과 관련하여 해당 우선 순위를 올바르게 설정하는 것입니다.

독자를위한 운동으로 너비와 동등한 작업을 수행합니다!


3
훌륭한 설명에 감사드립니다! 마지막으로 콘텐츠 포옹 우선 순위를 이해합니다.
kernix

Content Compression Resistance Priority가 무엇인지 설명해 주시겠습니까? 감사!
kernix

2
Excelente 답변 Max! 그런 식으로 작동하는 줄 수를 제한해야합니까?
rafaeljuzo

7

IOS7 sizeToFit에서도 작동하지 않습니다. 아마도 솔루션이 도움이 될 수 있습니다.

[textView sizeToFit];
[textView layoutIfNeeded];

1
@Rambatino 이것은 저에게 효과적입니다. layoutIfNeeded필요할 때 추가하십시오 setNeedsUpdateConstraints. 그러나 상황은 조금 다를 수 있습니다.
Gon

이것은 팝 오버를 할 때 가장 효과적이었습니다. 그래도 layoutIfNeeded를 먼저해야했습니다.
Jason

4

레이블의 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

4

올바른 솔루션을 찾는 데 시간이 걸렸으므로 기여해야한다고 생각합니다.

  • 목표는 sizeToFit ()를 호출하지 않고 자동 레이아웃이 작동하도록하는 것입니다. 올바른 제약 조건을 지정하여이 작업을 수행합니다.
  • UILabel에서 상단, 하단 및 선행 / 트레일 공간 제약 조건 지정
  • 줄 수 속성을 0으로 설정
  • 컨텐츠 포옹 우선 순위를 1000으로 증가
  • 내용 압축 저항 우선 순위를 500으로 낮추십시오
  • 하단 컨테이너 제약 조건에서 우선 순위를 500으로 낮추십시오.

기본적으로 UILabel에 고정 높이 제약 조건이 있지만 내용을 포옹하기 위해 제약 조건을 작게 만들 수 있지만 (예를 들어 한 줄이있는 경우) 구속 할 수는 없지만 더 크게 만들기 위해 구속 조건을 해제하십시오.


3

필자의 경우 UILabel (알 수없는 길이)이 포함 된 UIView 하위 클래스를 만들었습니다. iOS7에서는 코드가 간단했습니다. 제약 조건을 설정하고 콘텐츠 포옹이나 압축 저항에 대해 걱정하지 마십시오. 모든 것이 예상대로 작동했습니다.

그러나 iOS6에서는 UILabel이 항상 한 줄로 클리핑되었습니다. 위의 답변 중 어느 것도 나를 위해 일하지 않았습니다. 내용 포옹 및 압축 저항 설정은 무시되었습니다. 클리핑을 방지하는 유일한 해결책은 레이블에 preferredMaxLayoutWidth를 포함하는 것입니다. 그러나 부모 뷰의 크기를 알 수 없으므로 기본 너비를 무엇으로 설정 해야할지 알지 못했습니다 (실제로 내용으로 정의 됨).

드디어 해결책을 발견 여기에 . 사용자 정의보기에서 작업했기 때문에 제약 조건을 한 번 계산 한 후 선호하는 레이아웃 너비를 설정하기 위해 다음 방법을 추가 한 다음 다시 계산할 수 있습니다.

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

이것은 내가 가진 정확한 시나리오였습니다 ... 때로는 당신이 혼자가 아니라는 것을 아는 것이 좋습니다.
daveMac

아담, 나는 당신이 ios7에서 완벽하게 작동했다고 말한 것에 어려움을 겪고 있습니다. uiview와 uilabel이있는 사용자 정의 셀이 있습니다. 내용에 맞게 레이블을 가져올 수 있지만 어떤 제약 조건에 관계없이 뷰가 맞지 않습니다. 어떻게 작동하게 되었습니까? 나는 모든 것을 시도했지만 레이블의 높이를 차지하지 않는다고 맹세합니다
denikov

3

UILabel프로그래밍 방식으로 추가 하면 충분합니다.

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

2

xCode6을 사용하여 "선호 너비"를 자동으로 설정하고 레이블 상단, 앞뒤로 고정 여기에 이미지 설명을 입력하십시오


0
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));

0

내부 요소 인 경우 UILabel을 포함하는 UIView 하위 클래스 에서도이 문제가 발생했습니다. 자동 레이아웃과 권장 솔루션을 모두 사용해도 레이블의 높이는 텍스트에 맞게 조정되지 않습니다. 필자의 경우 레이블을 한 줄만 원합니다.

어쨌든, 나를 위해 일한 것은 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에서 완벽하게 작동합니다.


뷰를 올바르게 설정 한 경우 (즉, 구속 조건이 정확하고 뷰의 라이프 사이클에서 올바른 단계 동안 모든 것을 설정 한 경우) 재정의 할 필요가 없습니다 intrinsicContentSize. 런타임은 올바른 설정 제약 조건을 기반으로이를 계산할 수 있어야합니다.
존 로저스

이론적으로는 정확하지만 Apple의 모든 개인 API 및 구현에 액세스 할 수는 없으며 코드에 버그가 없습니다.
n8tr

...하지만 [super intrinsicContentSize]가 처리해야합니다. 자동 레이아웃을 올바르게 구현 한 경우
John Rogers

0

나를 위해 일한 솔루션; UILabel의 너비가 고정 되어 있으면 인터페이스 파일에서 제약 조건을에서 constant =로 변경 constant <=하십시오.

여기에 이미지 설명을 입력하십시오


-1

필자의 경우 UITableViewCell에서 레이블을 사용하면 레이블의 크기가 조정되지만 높이가 테이블 셀 높이를 초과합니다. 이것이 나를 위해 일한 것입니다. Max MacLeod에 따라 셀 높이가 UITableViewAutomaticDimension으로 설정되어 있는지 확인했습니다.

이것을 init 또는 awakeFromNib에 추가 할 수 있습니다.

self.tableView.rowHeight = UITableViewAutomaticDimension.  

스토리 보드에서 셀을 선택하고 크기 관리자를 연 다음 '사용자 정의'확인란을 선택하여 행 높이가 "기본값"으로 설정되어 있는지 확인하십시오.

8.0에는 코드에서 설정해야하는 문제가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.