ios - uitableviewcell - uitableview selfsizing




동적 셀 레이아웃 및 변수 행 높이에 대해 UITableView의 자동 레이아웃 사용 (17)

가변 높이 UITableViewCell의 신속한 예제

Swift 3 업데이트 됨

윌리엄 후 주석의 신속한 대답은 훌륭하지만 처음 무언가를하는 것을 배울 때 간단하면서도 세부적인 단계를 갖는 데 도움이됩니다. 아래 예제는 변수 테스트 셀을 사용하여 UITableView 를 만드는 법을 배우는 동안 테스트 프로젝트입니다. Swift 에 대한 이 기본 UITableView 예제를 기반으로합니다.

완료된 프로젝트는 다음과 같아야합니다.

새 프로젝트 만들기

단일보기 응용 프로그램 일 수 있습니다.

코드 추가

새 Swift 파일을 프로젝트에 추가하십시오. 이름을 MyCustomCell로 지정하십시오. 이 클래스는 스토리 보드에서 셀에 추가 한보기의 콘센트를 보유합니다. 이 기본 예제에서는 각 셀에 하나의 레이블 만 갖습니다.

import UIKit
class MyCustomCell: UITableViewCell {
    @IBOutlet weak var myCellLabel: UILabel!
}

나중에이 콘센트를 연결합니다.

ViewController.swift를 열고 다음 내용이 있는지 확인하십시오.

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    let animals: [String] = [
        "Ten horses:  horse horse horse horse horse horse horse horse horse horse ",
        "Three cows:  cow, cow, cow",
        "One camel:  camel",
        "Ninety-nine sheep:  sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep baaaa sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep",
        "Thirty goats:  goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat "]

    // Don't forget to enter this in IB also
    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // delegate and data source
        tableView.delegate = self
        tableView.dataSource = self

        // Along with auto layout, these are the keys for enabling variable cell height
        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
        cell.myCellLabel.text = self.animals[indexPath.row]
        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

중요 사항:

  • 가변 셀 높이를 가능하게하는 것은 다음 두 줄의 코드입니다 (자동 레이아웃과 함께).

    tableView.estimatedRowHeight = 44.0
    tableView.rowHeight = UITableViewAutomaticDimension
    

스토리 보드 설치

보기 컨트롤러에 테이블보기를 추가하고 자동 레이아웃을 사용하여 네면에 고정하십시오. 그런 다음 표보기 셀을 표보기로 끌어옵니다. Prototype 셀에 Label을 드래그합니다. 자동 레이아웃을 사용하여 레이블을 표보기 셀의 내용보기의 네 가장자리에 고정하십시오.

중요 사항:

  • 자동 레이아웃은 위에서 언급 한 중요한 두 줄의 코드와 함께 작동합니다. 자동 레이아웃을 사용하지 않으면 작동하지 않습니다.

기타 IB 설정

사용자 정의 클래스 이름 및 식별자

표보기 셀을 선택하고 사용자 정의 클래스를 MyCustomCell (우리가 추가 한 Swift 파일의 클래스 이름)으로 설정하십시오. 또한 Identifier를 cell (위의 코드에서 cellReuseIdentifier 에 사용한 것과 같은 문자열)로 설정하십시오.

라벨 용 제로 라인

라벨에 줄 수를 0 으로 설정하십시오. 이는 여러 줄을 의미하며 레이블을 내용에 따라 크기를 조정할 수 있습니다.

아울렛 연결

  • 스토리 보드의 테이블 뷰에서 ViewController 코드의 tableView 변수로 컨트롤을 드래그하십시오.
  • Prototype 셀의 Label에 대해 MyCustomCell 클래스의 myCellLabel 변수에 대해 동일한 작업을 수행하십시오.

끝마친

이제 프로젝트를 실행하고 다양한 높이의 셀을 가져올 수 있어야합니다.

노트

  • 이 예제는 iOS 8 이상에서만 작동합니다. iOS 7을 계속 지원해야하는 경우이 기능은 사용할 수 없습니다.
  • 향후 프로젝트의 사용자 지정 셀에는 단일 레이블 이상이있을 것입니다. 자동 레이아웃이 사용할 올바른 높이를 결정할 수 있도록 모든 것을 올바르게 고정해야합니다. 수직 압축 저항과 껴안기를 사용해야 할 수도 있습니다. 이에 대한 자세한 내용은 이 기사 를 참조하십시오.
  • 선행 및 후행 (왼쪽 및 오른쪽) 모서리를 고정하지 않을 경우 줄 바꿈 선을 알 수 있도록 레이블의 preferredMaxLayoutWidth 를 설정해야 할 수도 있습니다. 예를 들어, 선행 및 후행 가장자리를 고정하는 대신 위 프로젝트의 레이블에 Center Horizontally 구속 조건을 추가 한 경우이 선을 tableView:cellForRowAtIndexPath 메서드에 추가해야합니다.

     cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width
    

또한보십시오

부드러운 화면 이동 성능을 유지하면서 각 셀의 내용과 하위 뷰가 행 높이 (자체 / 자동)를 결정할 수 있도록 테이블보기에서 UITableViewCell 의 자동 레이아웃을 어떻게 사용합니까?


나는 스마일 보그의 iOS7 솔루션을 카테고리에 싸 다.

UICollectionViewCell+AutoLayoutDynamicHeightCalculation 범주에 UICollectionViewCell+AutoLayoutDynamicHeightCalculation 에 의해이 똑똑한 솔루션을 포장하기로 결정했습니다.

이 범주는 또한 @ wildmonkey의 답변 (펜촉에서 셀로드 및 systemLayoutSizeFittingSize: CGRectZero 반환)

아무런 캐싱도 고려하지 않지만 지금 당장 필요한 것입니다. 자유롭게 복사하여 붙여 넣기하고 해킹 할 수 있습니다.

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h

#import <UIKit/UIKit.h>

typedef void (^UICollectionViewCellAutoLayoutRenderBlock)(void);

/**
 *  A category on UICollectionViewCell to aid calculating dynamic heights based on AutoLayout contraints.
 *
 *  Many thanks to @smileyborg and @wildmonkey
 *
 *  @see .com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights
 */
@interface UICollectionViewCell (AutoLayoutDynamicHeightCalculation)

/**
 *  Grab an instance of the receiving type to use in order to calculate AutoLayout contraint driven dynamic height. The method pulls the cell from a nib file and moves any Interface Builder defined contrainsts to the content view.
 *
 *  @param name Name of the nib file.
 *
 *  @return collection view cell for using to calculate content based height
 */
+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name;

/**
 *  Returns the height of the receiver after rendering with your model data and applying an AutoLayout pass
 *
 *  @param block Render the model data to your UI elements in this block
 *
 *  @return Calculated constraint derived height
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width;

/**
 *  Directly calls `heightAfterAutoLayoutPassAndRenderingWithBlock:collectionViewWidth` assuming a collection view width spanning the [UIScreen mainScreen] bounds
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block;

@end

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m

#import "UICollectionViewCell+AutoLayout.h"

@implementation UICollectionViewCell (AutoLayout)

#pragma mark Dummy Cell Generator

+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name
{
    UICollectionViewCell *heightCalculationCell = [[[NSBundle mainBundle] loadNibNamed:name owner:self options:nil] lastObject];
    [heightCalculationCell moveInterfaceBuilderLayoutConstraintsToContentView];
    return heightCalculationCell;
}

#pragma mark Moving Constraints

- (void)moveInterfaceBuilderLayoutConstraintsToContentView
{
    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        [self removeConstraint:constraint];
        id firstItem = constraint.firstItem == self ? self.contentView : constraint.firstItem;
        id secondItem = constraint.secondItem == self ? self.contentView : constraint.secondItem;
        [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:firstItem
                                                                     attribute:constraint.firstAttribute
                                                                     relatedBy:constraint.relation
                                                                        toItem:secondItem
                                                                     attribute:constraint.secondAttribute
                                                                    multiplier:constraint.multiplier
                                                                      constant:constraint.constant]];
    }];
}

#pragma mark Height

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block
{
    return [self heightAfterAutoLayoutPassAndRenderingWithBlock:block
                                            collectionViewWidth:CGRectGetWidth([[UIScreen mainScreen] bounds])];
}

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width
{
    NSParameterAssert(block);

    block();

    [self setNeedsUpdateConstraints];
    [self updateConstraintsIfNeeded];

    self.bounds = CGRectMake(0.0f, 0.0f, width, CGRectGetHeight(self.bounds));

    [self setNeedsLayout];
    [self layoutIfNeeded];

    CGSize calculatedSize = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    return calculatedSize.height;

}

@end

사용 예 :

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYSweetCell *cell = [MYSweetCell heightCalculationCellFromNibWithName:NSStringFromClass([MYSweetCell class])];
    CGFloat height = [cell heightAfterAutoLayoutPassAndRenderingWithBlock:^{
        [(id<MYSweetCellRenderProtocol>)cell renderWithModel:someModel];
    }];
    return CGSizeMake(CGRectGetWidth(self.collectionView.bounds), height);
}

고맙게도 iOS8에서이 재즈를 할 필요는 없지만 지금은 있습니다!


여기 내 해결책이있다. 뷰를로드하기 전에 estimatedHeight를 TableView에 전달해야합니다. 그렇지 않으면 예상대로 작동하지 않을 것입니다.

목표 -C

- (void)viewWillAppear:(BOOL)animated {
    _messageField.delegate = self;
    _tableView.estimatedRowHeight = 65.0;
    _tableView.rowHeight = UITableViewAutomaticDimension;
}

Swift 4.2로 업데이트

override func viewWillAppear(_ animated: Bool) {
    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 65.0
}

(하단의 Xcode 8.x / Xcode 9.x 용)

혼란의 원인이 될 수있는 Xcode 7.x에서 다음 문제를주의하십시오.

Interface Builder는 자동 크기 조정 셀 설정을 올바르게 처리하지 못합니다. 귀하의 제약 조건이 절대적으로 유효하다고하더라도 IB는 여전히 불만을 제기하고 혼란스러운 제안과 오류를 줄 것입니다. 그 이유는 IB가 구속 조건에 따라 행의 높이를 변경하지 않기 때문입니다 (셀이 콘텐츠 주위에 맞도록). 대신 행의 높이를 고정시키고 제약 조건을 변경하라는 제안을 시작합니다 . 무시해야합니다 .

예를 들어 모든 것을 잘 설정했거나 경고도없고 오류도없고 모든 작업을 설정했다고 상상해보십시오.

이제 글꼴 크기를 변경하면 (이 예제에서는 설명 레이블 글꼴 크기를 17.0에서 18.0으로 변경).

글꼴 크기가 증가했기 때문에 이제 레이블은 3 행 (2 행을 차지하기 전에)을 차지하려고합니다.

Interface Builder가 예상대로 작동하면 새 레이블 높이를 수용하도록 셀의 높이가 조정됩니다. 그러나 실제로는 IB가 빨간색 자동 레이아웃 오류 아이콘을 표시하고 포옹 / 압축 우선 순위를 수정하도록 제안합니다.

이 경고는 무시해야합니다. 할 수있는 일은 행의 높이를 수동으로 변경하는 것입니다 (셀> 크기 속성> 행 높이 선택).

빨간색 화살표 오류가 사라질 때까지 한 번에 한 번씩이 높이를 변경했습니다 (위쪽 / 아래쪽 스테퍼 사용). (당신은 실제로 노란 경고를 받게 될 것입니다. 그 시점에서 '프레임 업데이트'를하면 모든 것이 작동합니다).

* 인터페이스 작성기에서 이러한 빨간색 오류 또는 노란색 경고를 실제로 해결할 필요는 없습니다. 런타임에 IB가 오류 / 경고를 표시하더라도 모든 것이 올바르게 작동합니다. 콘솔 로그의 런타임에 AutoLayout 오류가 발생하지 않도록하십시오.

사실 IB에서 행 높이를 항상 업데이트하려고 시도하는 것은 매우 성가 시며 때로는 불가능한 경우도 있습니다 (분수 값 때문).

귀찮은 IB 경고 / 오류를 방지하기 위해, 당신의 의견은 참여와에서 선택할 수있는 Size Inspector속성에 대한 Ambiguity선택Verify Position Only

Xcode 8.x / Xcode 9.x는 (때로는) Xcode 7.x와는 다른 방식으로 작동하는 것처럼 보이지만 여전히 잘못된 것 같습니다. 예를 들어 compression resistance priority/ hugging priority가 required (1000)로 설정된 경우에도 Interface Builder는 레이블 주위에 맞게 셀 높이의 크기를 조정하는 대신 셀에 맞게 레이블을 늘리거나자를 수 있습니다. 그리고 이런 경우에는 AutoLayout 경고 또는 오류조차 보이지 않을 수도 있습니다. 또는 때로는 Xcode 7.x가 정확히 무엇을했는지를 위에서 설명했습니다.


TL : DR : 독서를 좋아하지 않습니까? GitHub의 샘플 프로젝트로 곧바로 이동하십시오 :

개념 설명

아래의 첫 번째 2 단계는 개발중인 iOS 버전에 관계없이 적용됩니다.

1. 제약 조건 설정 및 추가

UITableViewCell 하위 클래스에서 셀의 하위 뷰가 셀의 contentView 가장자리 (가장 중요하게는 위쪽 및 아래쪽 가장자리)에 고정되도록 구속 조건을 추가합니다. 참고 : 하위 자체를 셀 자체에 고정하지 마십시오. 셀의 contentView 에만! 이러한 하위 뷰의 본질적인 콘텐츠 크기가 각 하위 뷰의 수직 차원에서 콘텐츠 압축 저항콘텐츠 포옹 제한이 추가 한 우선 순위가 높은 제약 조건에 의해 무시되지 않도록하여 테이블 뷰 셀의 콘텐츠 뷰 높이를 높입니다. (어 ? 여기를 클릭하십시오. )

셀의 하위보기를 셀의 내용보기에 수직으로 연결하여 "압력을 가할 수 있고 내용보기를 내용보기에 맞게 만들 수 있습니다. 하위 뷰가 몇 개있는 예제 셀을 사용하면 다음과 같이 구속 조건 중 일부 (전부는 아님) 의 모양을 시각적으로 보여줍니다.

위의 예제 셀에있는 여러 줄의 본문 레이블에 더 많은 텍스트가 추가되면 텍스트를 맞추기 위해 세로로 늘어나야 만 효과적으로 셀의 높이가 증가하게됩니다. (물론이 작업을 올바르게 수행하려면 제약 조건을 가져와야합니다!)

귀하의 제약 조건을 올바르게 맞추는 것은 자동 레이아웃으로 동적 셀 높이를 얻는 데있어 가장 어렵고 중요한 부분 입니다. 여기서 실수를하면 다른 모든 것이 작동하지 않을 수 있습니다. 따라서 시간을 투자하십시오! 코드에서 제약 조건을 설정하는 것이 좋습니다. 제약 조건이 어디에 추가되는지 정확히 알기 때문이며, 상황이 잘못 될 경우 디버깅하는 것이 훨씬 쉽습니다. 코드에 제약 조건을 추가하는 것은 인터페이스 앵커를 사용하는 Interface Builder와 마찬가지로 쉽고 훨씬 강력 할 수 있습니다. GitHub에서 사용할 수있는 환상적인 오픈 소스 API 중 하나입니다.

  • 코드에 제약 조건을 추가하려면 UITableViewCell 하위 클래스의 updateConstraints 메서드 내에서이 작업을 한 번 수행해야합니다. updateConstraints 는 두 번 이상 호출 될 수 있으므로 동일한 제약 조건을 두 번 이상 추가하지 않으려면 didSetupConstraints 와 같은 부울 속성 검사에서 updateConstraints 내에 제약 조건 추가 코드를 래핑해야합니다 (예 : 한 번 제약 조건 추가 코드를 실행하십시오.) 반면에 기존 제약 조건을 업데이트하는 코드 (예 : 일부 제약 조건의 constant 속성 조정)가있는 경우이 값을 updateConstraintsdidSetupConstraints 검사를 didSetupConstraints 면 메소드가 호출 될 때마다 실행할 수 있습니다.

2. 고유 테이블보기 셀 재사용 식별자 결정

셀의 모든 고유 한 제약 조건 집합에 대해 고유 한 셀 재사용 식별자를 사용합니다. 즉, 셀에 고유 레이아웃이 두 ​​개 이상있는 경우 각 고유 레이아웃에는 고유 한 재사용 식별자가 있어야합니다. 새 재사용 식별자를 사용해야하는 좋은 힌트는 셀 변형에 다른 수의 하위보기가 있거나 하위보기가 별개의 방식으로 정렬되어있는 경우입니다.

예를 들어 각 셀에 전자 메일 메시지를 표시하는 경우 제목이 단락 인 메시지, 제목과 본문이있는 메시지, 제목과 사진 첨부 파일이있는 메시지, 제목이있는 메시지 등 4 가지 고유 한 레이아웃이있을 수 있습니다. 신체 및 사진 부착. 각 레이아웃에는이를 달성하는 데 필요한 완전히 다른 제약 조건이 있으므로 셀이 초기화되고 이러한 셀 유형 중 하나에 대한 제약 조건이 추가되면 셀은 해당 셀 유형에 고유 한 고유 한 재사용 식별자를 가져야합니다. 즉, 재사용을 위해 셀을 큐에서 제거 할 때 제약 조건이 이미 추가되어 해당 셀 유형을 사용할 준비가되었습니다.

고유 한 콘텐츠 크기의 차이로 인해 동일한 제약 조건 (유형)이있는 셀의 높이가 여전히 다양 할 수 있습니다. 콘텐츠의 크기가 다르기 때문에 근본적으로 다른 레이아웃 (다른 제약 조건)과 다른 계산 된 뷰 프레임 (동일한 제약 조건에서 해결됨)을 혼동하지 마십시오.

  • 동일한 재사용 풀에 완전히 다른 제약 조건 집합을 가진 셀을 추가하지 마십시오 (예 : 동일한 재사용 식별자 사용). 그런 다음 기존 제약 조건을 제거하고 각 대기열 제거 후 처음부터 새 제약 조건을 설정하십시오. 내부 자동 레이아웃 엔진은 제약 조건의 대규모 변경을 처리하도록 설계되지 않았으므로 대규모 성능 문제가 발생합니다.

iOS 8 - 셀프 크기 조정 셀

3. 행 높이 추정 사용

자체 크기 조정 테이블 뷰 셀을 사용하려면 테이블 뷰의 rowHeight 속성을 UITableViewAutomaticDimension으로 설정해야합니다. estimatedRowHeight 속성에도 값을 할당해야합니다. 이 두 속성이 모두 설정되면 시스템은 자동 레이아웃을 사용하여 행의 실제 높이를 계산합니다

Apple : 자체 크기 조정 표보기 셀 작업

iOS 8을 사용하면 Apple은 이전에 iOS 8 이전에 구현해야했던 많은 작업을 내부화했습니다. 자체 크기 조정 셀 메커니즘이 작동하도록하려면 먼저 테이블보기에서 rowHeight 속성을 상수 UITableViewAutomaticDimension . 그런 다음 테이블 뷰의 estimatedRowHeight 속성을 0이 아닌 값으로 설정하여 행 높이 추정을 활성화하면됩니다. 예를 들면 다음과 같습니다.

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0; // set to whatever your "average" cell height is

이것은 테이블 뷰에 아직 화면 상에없는 셀의 행 높이에 대한 임시 추정값 / 자리 표시자를 제공하는 것입니다. 그런 다음이 셀이 화면에서 스크롤하려고하면 실제 행 높이가 계산됩니다. 각 행의 실제 높이를 결정하기 위해 테이블 ​​뷰는 content view의 알려진 고정 너비 (표보기의 너비에서 섹션과 같은 추가 항목을 뺀 값을 기준으로 contentView 높이를 자동으로 각 셀에 요청합니다 인덱스 또는 액세서리보기) 및 셀의 내용보기 및 하위보기에 추가 한 자동 레이아웃 제약 조건이 있습니다. 이 실제 셀 높이가 결정되면 행에 대한 이전 예상 높이가 새로운 실제 높이로 업데이트됩니다 (그리고 필요에 따라 테이블 뷰의 contentSize / contentOffset에 대한 조정이 이루어짐).

일반적으로 사용자가 제공하는 견적은 매우 정확할 필요는 없습니다. 이는 테이블보기에서 스크롤 표시기의 크기를 올바르게 지정하는 데 사용되며 테이블보기는 잘못된 견적에 대한 스크롤 표시기를 조정하는 역할을합니다 화면을 스크롤하십시오. table 뷰의 estimatedRowHeight 속성 ( viewDidLoad 또는 유사)을 "평균"행 높이 인 상수 값으로 설정해야합니다. 행 높이가 극단적 인 가변성 (예 : 크기 순서가 다름)이 있고 스크롤 할 때 scroll 표시기가 " tableView:estimatedHeightForRowAtIndexPath: 더 정확한 계산을 위해 필요한 최소한의 계산 만 수행하면 스크롤 할 때"점프하는 것을 볼 수 있습니다. 각 행.

iOS 7 지원 (자동 셀 크기 조정 구현)

3. 레이아웃 패스 및 셀 높이 얻기

먼저, 높이 계산에 엄격하게 사용되는 각 재사용 식별자에 대해 하나의 인스턴스 인 테이블 뷰 셀의 화면 외 인스턴스를 인스턴스화합니다. (셀 참조가 뷰 컨트롤러의 속성 / ivar에 저장되고 실제로는 tableView:cellForRowAtIndexPath: 에서 반환되지 않음을 의미하는 화면 꺼짐) 다음에 셀은 정확한 내용 (예 : 텍스트, 이미지 등)가 테이블 뷰에 표시 될 경우 보유합니다.

그런 다음 셀을 하위 뷰의 레이아웃을 즉시 systemLayoutSizeFittingSize: UITableViewCellcontentView 에서 systemLayoutSizeFittingSize: 메서드를 사용하여 셀의 필요한 높이를 확인합니다. UILayoutFittingCompressedSize 를 사용하여 셀의 모든 내용을 맞추는 데 필요한 최소 크기를 가져옵니다. 그런 다음 height는 tableView:heightForRowAtIndexPath: delegate 메소드에서 반환 할 수 있습니다.

4. 예상 행 높이 사용

테이블 뷰에 수십 개의 행이 있으면 자동 레이아웃 제약 조건 해결을 수행하면 테이블 뷰를 처음로드 할 때 주 스레드가 tableView:heightForRowAtIndexPath: 는 각 행마다 호출 됨) 첫 번째로드시 (스크롤 표시기의 크기를 계산하기 위해)

iOS 7부터는 테이블 뷰에서 estimatedRowHeight 속성을 사용할 수 있습니다 (그리고 절대적으로 사용해야 함). 이것은 테이블 뷰에 아직 화면 상에없는 셀의 행 높이에 대한 임시 추정값 / 자리 표시자를 제공하는 것입니다. 그런 다음이 셀이 화면에서 스크롤하려고하면 실제 행 높이가 계산되고 ( tableView:heightForRowAtIndexPath: 를 호출하여) 예상 높이가 실제 높이로 업데이트됩니다.

일반적으로 사용자가 제공하는 견적은 매우 정확할 필요는 없습니다. 이는 테이블보기에서 스크롤 표시기의 크기를 올바르게 지정하는 데 사용되며 테이블보기는 잘못된 견적에 대한 스크롤 표시기를 조정하는 역할을합니다 화면을 스크롤하십시오. table 뷰의 estimatedRowHeight 속성 ( viewDidLoad 또는 유사)을 "평균"행 높이 인 상수 값으로 설정해야합니다. 행 높이가 극단적 인 가변성 (예 : 크기 순서가 다름)이 있고 스크롤 할 때 scroll 표시기가 " tableView:estimatedHeightForRowAtIndexPath: 더 정확한 계산을 위해 필요한 최소한의 계산 만 수행하면 스크롤 할 때"점프하는 것을 볼 수 있습니다. 각 행.

5. (필요한 경우) 행 높이 캐싱 추가

위의 모든 작업을 수행하고 tableView:heightForRowAtIndexPath: 에서 제약 조건 해결을 수행 할 때 성능이 허용 할 수 없을 정도로 느린 경우 여전히 불행히도 셀 높이에 대한 캐싱을 구현해야합니다. (이것은 Apple의 엔지니어가 제안한 접근 방식입니다.) 일반적으로 자동 레이아웃 엔진이 처음으로 제약 조건을 풀고 그 셀의 계산 된 높이를 캐싱 한 다음 그 셀의 높이에 대한 모든 향후 요청에 캐시 된 값을 사용하는 것이 일반적입니다. 트릭은 물론 셀의 높이가 변경 될 수있는 상황이 발생했을 때 셀의 캐시 된 높이를 지우는 것입니다. 주로 셀의 내용이 변경되거나 다른 중요한 이벤트가 발생할 때 (예 : 사용자 조정 동적 유형 텍스트 크기 슬라이더).

iOS 7 일반 샘플 코드 (수분이 많은 댓글이 많음)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path, depending on the particular layout required (you may have
    // just one, or may have many).
    NSString *reuseIdentifier = ...;

    // Dequeue a cell for the reuse identifier.
    // Note that this method will init and return a new cell if there isn't
    // one available in the reuse pool, so either way after this line of 
    // code you will have a cell with the correct constraints ready to go.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // If you are using multi-line UILabels, don't forget that the 
    // preferredMaxLayoutWidth needs to be set correctly. Do it at this 
    // point if you are NOT doing it within the UITableViewCell subclass 
    // -[layoutSubviews] method. For example: 
    // cell.multiLineLabel.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds);

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path.
    NSString *reuseIdentifier = ...;

    // Use a dictionary of offscreen cells to get a cell for the reuse 
    // identifier, creating a cell and storing it in the dictionary if one 
    // hasn't already been added for the reuse identifier. WARNING: Don't 
    // call the table view's dequeueReusableCellWithIdentifier: method here 
    // because this will result in a memory leak as the cell is created but 
    // never returned from the tableView:cellForRowAtIndexPath: method!
    UITableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
    if (!cell) {
        cell = [[YourTableViewCellClass alloc] init];
        [self.offscreenCells setObject:cell forKey:reuseIdentifier];
    }

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // Set the width of the cell to match the width of the table view. This
    // is important so that we'll get the correct cell height for different
    // table view widths if the cell's height depends on its width (due to 
    // multi-line UILabels word wrapping, etc). We don't need to do this 
    // above in -[tableView:cellForRowAtIndexPath] because it happens 
    // automatically when the cell is used in the table view. Also note, 
    // the final width of the cell may not be the width of the table view in
    // some cases, for example when a section index is displayed along 
    // the right side of the table view. You must account for the reduced 
    // cell width.
    cell.bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

    // Do the layout pass on the cell, which will calculate the frames for 
    // all the views based on the constraints. (Note that you must set the 
    // preferredMaxLayoutWidth on multi-line UILabels inside the 
    // -[layoutSubviews] method of the UITableViewCell subclass, or do it 
    // manually at this point before the below 2 lines!)
    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    // Get the actual height required for the cell's contentView
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    // Add an extra point to the height to account for the cell separator, 
    // which is added between the bottom of the cell's contentView and the 
    // bottom of the table view cell.
    height += 1.0;

    return height;
}

// NOTE: Set the table view's estimatedRowHeight property instead of 
// implementing the below method, UNLESS you have extreme variability in 
// your row heights and you notice the scroll indicator "jumping" 
// as you scroll.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Do the minimal calculations required to be able to return an 
    // estimated row height that's within an order of magnitude of the 
    // actual height. For example:
    if ([self isTallCellAtIndexPath:indexPath]) {
        return 350.0;
    } else {
        return 40.0;
    }
}

샘플 프로젝트

이 프로젝트는 UILabels에서 동적 컨텐트를 포함하는 테이블 뷰 셀로 인해 다양한 행 높이를 갖는 테이블 뷰의 완전한 작동 예제입니다.

Xamarin (C # / .NET)

Xamarin을 사용하는 경우 @KentBoogaart가 조립 한이 샘플 프로젝트를 확인하십시오.


@smileyborg의 답변에 관해서는

[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]

제약이 모호한 경우에는 신뢰할 수 없다. 아래의 UIView에서 도우미 카테고리를 사용하여 한 방향으로 높이를 계산하도록 레이아웃 엔진을 강제하는 것이 좋습니다.

-(CGFloat)systemLayoutHeightForWidth:(CGFloat)w{
    [self setNeedsLayout];
    [self layoutIfNeeded];
    CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(w, 1) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
    CGFloat h = size.height;
    return h;
}

여기서 w :는 테이블 뷰의 너비입니다.


동적 뷰 (설정보기 및 코드에 의한 제약 조건)를 사용해야하고 preferredMaxLayoutWidth를 설정하려고 할 때 라벨의 너비는 0이었습니다. 따라서 셀 높이가 잘못되었습니다.

그럼 나는 덧붙였다.

[cell layoutSubviews];

실행 전에

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

레이블의 너비가 예상대로되고 동적 높이가 오른쪽으로 계산 된 후에.


또 다른 "솔루션":이 모든 좌절감을 피하고 대신 UIScrollView를 사용하여 UITableView와 동일한 모양과 느낌의 결과를 얻으십시오.

필자는 스마일 보그가 제안한 것과 같이 앱 스토어 출시의 여러 달과 3 개월 동안 실패한 것 같은 것을 구축하기 위해 총 20 개 이상의 매우 초조 한 시간을 넣은 후 저에게는 고통스런 "해결책"이었습니다.

제 취업은 iOS 7 지원이 필요하다면 (우리에게는 필수적입니다) 그 기술은 너무 부서지기 쉽습니다. 그리고 UITableView는 고급 행 편집 기능을 사용하거나 1000 개 이상의 "행"을 지원해야하는 경우가 아니면 일반적으로 과도한 작업입니다 (앱에서는 실제로 20 행을 넘지 않습니다).

추가 된 보너스는 코드가 UITableView에서 제공되는 모든 위임자 쓰레기와 앞뒤로 대단히 단순해진다는 것입니다. viewOnLoad의 코드 루프는 우아하고 관리하기 쉽습니다.

방법은 다음과 같습니다.

1) Storyboard 또는 nib 파일을 사용하여 ViewController 및 연관된 루트 뷰를 작성하십시오.

2) UIScrollView를 루트보기로 끌어옵니다.

3) UIScrollView가 전체 루트 뷰를 채울 수 있도록 맨 위 레벨 뷰에 제약 조건의 위쪽, 아래쪽, 왼쪽 및 오른쪽 제약 조건을 추가합니다.

4) UIView를 UIScrollView 내부에 추가하고 "컨테이너"라고 부릅니다. 위쪽, 아래쪽, 왼쪽 및 오른쪽 제약 조건을 UIScrollView (부모)에 추가합니다. 키 트릭 : UIScrollView와 UIView를 링크하기 위해 "Equal widths"제약 조건을 추가하십시오.

"스크롤 뷰의 스크롤 가능한 내용 높이가 모호합니다"라는 오류가 표시되고 컨테이너 UIView의 높이가 0 픽셀이어야합니다. 앱이 실행 중일 때도 오류가 중요하지 않습니다.

5) 각 "셀"에 대해 nib 파일과 컨트롤러를 만듭니다. UITableViewCell이 아닌 UIView를 사용하십시오.

5) 루트 ViewController에서 기본적으로 모든 "행"을 컨테이너 UIView에 추가하고 왼쪽 및 오른쪽 가장자리를 컨테이너보기에 연결하는 제약 조건을 프로그래밍 방식으로 추가하고, 위쪽 가장자리를 컨테이너보기 상단 (첫 번째 항목의 경우) 또는 이전 셀. 그런 다음 마지막 셀을 컨테이너 바닥에 연결하십시오.

우리에게는 각 "행"이 nib 파일에 있습니다. 그래서 코드는 다음과 같이 보입니다.

class YourRootViewController {

    @IBOutlet var container: UIView! //container mentioned in step 4

    override func viewDidLoad() {

        super.viewDidLoad()

        var lastView: UIView?
        for data in yourDataSource {

            var cell = YourCellController(nibName: "YourCellNibName", bundle: nil)
            UITools.addViewToTop(container, child: cell.view, sibling: lastView)
            lastView = cell.view
            //Insert code here to populate your cell
        }

        if(lastView != nil) {
            container.addConstraint(NSLayoutConstraint(
                item: lastView!,
                attribute: NSLayoutAttribute.Bottom,
                relatedBy: NSLayoutRelation.Equal,
                toItem: container,
                attribute: NSLayoutAttribute.Bottom,
                multiplier: 1,
                constant: 0))
        }

        ///Add a refresh control, if you want - it seems to work fine in our app:
        var refreshControl = UIRefreshControl()
        container.addSubview(refreshControl!)
    }
}

다음은 UITools.addViewToTop의 코드입니다.

class UITools {
    ///Add child to container, full width of the container and directly under sibling (or container if sibling nil):
    class func addViewToTop(container: UIView, child: UIView, sibling: UIView? = nil)
    {
        child.setTranslatesAutoresizingMaskIntoConstraints(false)
        container.addSubview(child)

        //Set left and right constraints so fills full horz width:

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Leading,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Left,
            multiplier: 1,
            constant: 0))

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Trailing,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Right,
            multiplier: 1,
            constant: 0))

        //Set vertical position from last item (or for first, from the superview):
        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Top,
            relatedBy: NSLayoutRelation.Equal,
            toItem: sibling == nil ? container : sibling,
            attribute: sibling == nil ? NSLayoutAttribute.Top : NSLayoutAttribute.Bottom,
            multiplier: 1,
            constant: 0))
    }
}

지금까지이 접근법에서 발견 된 유일한 "잡았다"는 스크롤 할 때 UITableView가 뷰 상단에 "유동"섹션 헤더라는 멋진 기능을 가지고 있다는 것입니다. 위의 해결책은 더 많은 프로그래밍을 추가하지 않는 한 그렇게하지 않을 것입니다. 그러나 우리의 특별한 경우에이 기능은 100 % 필수적이지 않으며 사라지지 않을 때 아무도 눈치 채지 못했습니다.

셀 사이에 구분선을 사용하려면 구분선처럼 보이는 사용자 정의 "셀"의 하단에 1 픽셀 높이의 UIView를 추가하십시오.

새로 고침 컨트롤이 작동하도록 "튀어 오르게"및 "수직으로 튀어 오르게"설정해야 테이블 뷰와 같은 느낌을 줄 수 있습니다.

TableView는이 솔루션과 같이 전체 화면을 채우지 않는 경우 콘텐츠 아래에 일부 빈 행과 구분선을 표시합니다. 그러나 개인적으로, 나는 그 빈 행이 어쨌든 존재하지 않는다면 선호한다. 가변 셀 높이를 사용하면 항상 빈 행을 가지기 위해 항상 "버기"가된다.

다른 프로그래머가 20 시간 이상 낭비하기 전에 내 게시물을 읽고 자신의 응용 프로그램에서 Table View로 파악하려고하기를 바랍니다. :)


중요한 대답은 내가 방금 답변을 게시하기 위해 만났습니다.

@ smileyborg의 대답은 대체로 정확합니다. 그러나 layoutSubviews사용자 정의 셀 클래스 의 메소드에 코드가있는 경우 ( 예 :를 설정 preferredMaxLayoutWidth한 경우)이 코드로 실행되지 않습니다.

[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];

그것은 나를 당황하게했다. 그 다음에 contentView는 셀 자체가 아닌 layoutSubviews 만 트리거하기 때문에 그 사실을 깨달았습니다 .

내 작업 코드는 다음과 같습니다.

TCAnswerDetailAppSummaryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailAppSummaryCell"];
[cell configureWithThirdPartyObject:self.app];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;

새 셀을 만드는 경우 setNeedsLayout이미 설정되어 있어야 하므로 전화 할 필요가 없습니다 . 셀에 대한 참조를 저장하는 경우 아마도 호출해야합니다. 어느 쪽이든 그것은 아무 것도 해치지 않아야합니다.

당신이 물건을 설정하고있는 곳에서 셀 서브 클래스를 사용한다면 또 다른 팁 preferredMaxLayoutWidth. @smileyborg는 "귀하의 테이블 뷰 셀의 테이블 뷰 너비에 고정 된 너비가 아직 없습니다"라고 언급합니다. 뷰 컨트롤러가 아닌 하위 클래스에서 작업하는 경우 문제가 발생합니다. 그러나 테이블 너비를 사용하여이 시점에서 셀 프레임을 간단히 설정할 수 있습니다.

예를 들어 높이 계산 :

self.summaryCell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailDefaultSummaryCell"];
CGRect oldFrame = self.summaryCell.frame;
self.summaryCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, self.tableView.frame.size.width, oldFrame.size.height);

(나는 재사용을 위해이 특정 셀을 캐시하지만 우연히는 그렇지 않다).


처럼 나는 이것을 중요한 답변으로 게시 할 정도로 중요한 문제에 .

나는 @smileyborg's 대답으로 잠시 고투했다 . 당신이 (추가 요소와 IB에 프로토 타입 셀을 정의 한 경우 I는 퉜다 잡았다 UILabels, UIButtons당신이 셀을 인스턴스화 할 때 IB에, 등) [YourTableViewCellClass alloc] init]당신이했습니다 않는 한 해당 셀 내의 다른 모든 요소를 인스턴스화 할 것 그렇게하기 위해 작성된 코드. (나는 비슷한 경험을했다 initWithStyle.)

스토리 보드에서 모든 추가 요소를 인스턴스화하게하려면 흥미로운 문제가 발생 [tableView dequeueReusableCellWithIdentifier:@"DoseNeeded"]하지 않는 한 셀을 가져 오십시오 [tableView dequeueReusableCellWithIdentifier:forIndexPath:]. 이렇게하면 IB에서 정의한 모든 요소가 인스턴스화됩니다.


필자의 경우, padding은 sectionHeader와 sectionFooter height 때문에 발생했으며, storyboard를 사용하면 최소 1로 변경할 수있었습니다. 따라서 viewDidLoad 메서드에서 :

tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0

하위보기가있는 셀이 있고 셀의 높이가 하위보기 + 패딩을 포함 할만큼 충분히 높기를 원한다고 가정 해 봅시다.

1) 하위보기의 아래쪽 제약 조건을 cell.contentView에서 원하는 패딩 빼기로 설정합니다. 셀 또는 cell.contentView 자체에 제약 조건을 설정하지 마십시오.

2) tableView의 rowHeight속성이나 tableView:heightForRowAtIndexPath:를 설정하십시오 UITableViewAutomaticDimension.

3) tableView의 estimatedRowHeight속성이나 tableView:estimatedHeightForRowAtIndexPath:높이를 가장 잘 추측하도록 설정하십시오 .

그게 전부 야.


@smileyborg가 제안한 해결책은 거의 완벽합니다. 사용자 정의 셀이 있고 UILabel동적 높이가 하나 이상인 경우 autoLayout 과 함께 사용 되는 systemLayoutSizeFittingSize 메소드는 CGSizeZero셀의 모든 컨 스트레인 트를 셀에서 contentView로 이동하지 않는 한 a를 반환합니다 (@TomSwift가 제안한 것처럼 여기에서 수퍼 뷰의 크기를 조정하는 방법). autolayout으로 모든 하위 뷰를 맞 춥니 다? ).

그렇게하려면 사용자 정의 UITableViewCell 구현 (@Adrian 덕분에)에 다음 코드를 삽입해야합니다.

- (void)awakeFromNib{
    [super awakeFromNib];
    for (NSLayoutConstraint *cellConstraint in self.constraints) {
        [self removeConstraint:cellConstraint];
        id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
        id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
        NSLayoutConstraint *contentViewConstraint =
        [NSLayoutConstraint constraintWithItem:firstItem
                                 attribute:cellConstraint.firstAttribute
                                 relatedBy:cellConstraint.relation
                                    toItem:seccondItem
                                 attribute:cellConstraint.secondAttribute
                                multiplier:cellConstraint.multiplier
                                  constant:cellConstraint.constant];
        [self.contentView addConstraint:contentViewConstraint];
    }
}

이것과 @smileyborg 대답을 조합하면 효과가있다.


긴 문자열이 있다면. 줄 바꿈이없는 예. 그러면 몇 가지 문제가 발생할 수 있습니다.

해결 방법은 수락 된 대답과 몇 가지 다른 답변으로 언급됩니다. 추가하기 만하면됩니다.

cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width

나는 가장 혼란스럽지 만 Suragh의 대답 이 가장 완벽 하다고 느낍니다 .

이유는 설명 할 수 없지만 . 그걸하자.

다음 코드를 프로젝트에 놓습니다.

import UIKit

class ViewController: UIViewController {

    lazy var label : UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.backgroundColor = .red
        lbl.textColor = .black
        return lbl
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // step0: (0.0, 0.0)
        print("empty Text intrinsicContentSize: \(label.intrinsicContentSize)")
        // step1: (29.0, 20.5)
        label.text = "hiiiii"
        print("hiiiii intrinsicContentSize: \(label.intrinsicContentSize)")
        // step2: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints"
        print("1 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // step3: (992.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints"
        print("3 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // step4: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints"
        print("3 translate w/ line breaks intrinsicContentSize: \(label.intrinsicContentSize)") 
        // step5: (328.0, 61.0)
        label.numberOfLines = 0
        print("3 translate w/ line breaks and '0' numberOfLines intrinsicContentSize: \(label.intrinsicContentSize)") 
        // step6: (98.5, 243.5)
        label.preferredMaxLayoutWidth = 100
        print("3 translate w/ line breaks | '0' numberOfLines | preferredMaxLayoutWidth: 100 intrinsicContentSize: \(label.intrinsicContentSize)") 

        setupLayout()
    }
    func setupLayout(){
        view.addSubview(label)
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
}

크기 제한을 추가하지 않았습니다 . centerX, centerY 제약 조건 만 추가했습니다. 하지만 여전히 레이블의 크기가 올바르게 표시됩니다. 왜? 때문에 contentSize.

이를 더 잘 처리하려면 먼저 step0을 유지 한 다음 단계 1-6을 주석 처리하십시오. 있어 줘 setupLayout(). 행동을 관찰하십시오.

그런 다음 step1의 주석을 제거하고 관찰하십시오.

그런 다음 step2의 주석을 지우고 관찰하십시오.

6 단계를 모두 주석 처리하고 행동을 관찰 할 때까지하십시오.

이 모든 것으로부터 무엇을 결론 지을 수 있습니까? 어떤 요인이 변경 될 수 contenSize있습니까?

  1. 텍스트 길이 : 텍스트 가 길면 intrinsicContentSize의 너비 가 증가합니다.
  2. 줄 바꿈 :\n intrinsicContentSize의 너비 를 추가하면 모든 줄의 최대 너비가됩니다. 한 줄에 25 자, 다른 줄에 2 자, 다른 줄에 21자를 입력하면 너비가 25자를 기준으로 계산됩니다.
  3. 허용 라인 수 : 당신은 설정해야 numberOfLines0그렇지 않으면 여러 개의 전화 회선이되지 않습니다. 귀하의 numberOfLines것입니다 귀하의 intentinentContentSize의 높이를 조정합니다
  4. 조정하기 : 텍스트를 기반으로 intrinsicContentSize의 너비 200와 높이가 100같았지만 너는 라벨 컨테이너에 너비를 제한하고 싶다고 상상해보십시오 . 해결책은 원하는 너비로 설정하는 것입니다. 당신은 설정하여 그렇게 preferredMaxLayoutWidth130다음 새 intrinsicContentSize이 약의 폭을해야합니다 130. 높이는 분명히 100더 많은 선이 필요하기 때문일 것입니다. 귀하의 제약 조건이 올바르게 설정 되었다면 귀하는 이것을 전혀 사용할 필요가 없다고 말하고 있습니다! 그것에 대한 자세한 내용은 이 답변 과 그 코멘트 를 참조하십시오 . 당신은 사용할 필요가 preferredMaxLayoutWidth당신이이 값을 초과하지 않는 텍스트를 포장하지 않는다 "말할 수 하나 같이 너비 / 높이를 제한하는 제약 조건이없는 경우preferredMaxLayoutWidth". 그러나 100 % 확실하게 당신이 선두가 / 후행 및 설정하는 경우 numberOfLines0! 당신이 좋은 것 그것의 사용을 권장하는 여기에 길고도 짧은 이야기 대부분의 답변을 잘못! 당신은 그것을 필요하지 않습니다. 그것을 필요는 제약 조건 표시이다 올바르게 설정되지 않았거나 제약 조건이 없습니다.

  5. 글꼴 크기 : 또한 fontSize를 늘리면 intrinsicContentSize의 높이 가 증가합니다. 내 코드에서이를 보여주지 않았다. 당신 스스로 시도 할 수 있습니다.

그래서 다시 귀하의 tableViewCell 예제 :

당신이해야 할 모든 설정 numberOfLines0하고 설정 preferredMaxLayoutWidth당신에 tableViewwidth.


내 경우에는 서버에서 오는 이미지가있는 사용자 정의 셀을 만들고 너비와 높이가 될 수 있습니다. 그리고 동적 크기 (너비와 높이 모두)를 가진 두 개의 UILabels

autolayout 및 프로그래밍 방식으로 내 대답은 여기에 동일한 달성했습니다.

기본적으로 @smileyBorg는 도움이되었지만 systemLayoutSizeFittingSize는 절대로 작동하지 않았습니다. 내 접근 방식 :

1. 자동 행 높이 계산 특성을 사용하지 않습니다. 2. 예상 높이 사용 안 함. 3. 불필요한 업데이트 필요 없음. 4. 자동 권장 최대 레이아웃 너비 사용 안함. 5. systemLayoutSizeFittingSize 를 사용하지 않아야합니다 (사용 중이지만 작동하지 않아야합니다. 내부적으로 무엇을하는지 알지 못합니다.) 대신 내 메서드 - (부동) getViewHeight가 작동하고 내부적으로 무엇을하는지 알 수 있습니다.

셀을 표시하는 여러 가지 방법을 사용할 때 UITableView 셀의 높이가 다를 수 있습니까?


사람들이 여전히 문제가있는 경우. UITableViews와 함께 Autolayout을 사용하는 방법에 대한 간단한 블로그 게시물을 작성했습니다. 동적 셀 높이 를위한 Autolayout을 활용 하는 것뿐 아니라 오픈 소스 구성 요소를 사용하여이를보다 추상적으로 구현하기가 더 쉬워졌습니다. https://github.com/Raizlabs/RZCellSizeManager


tableView.estimatedRowHeight = 343.0
tableView.rowHeight = UITableViewAutomaticDimension





row-height