스토리 보드의 사용자 정의 셀 행 높이 설정이 응답하지 않습니다


213

테이블 뷰에서 셀 중 하나의 셀 높이를 조정하려고합니다. 해당 셀의 "크기 검사기"내의 "행 높이"설정에서 크기를 조정하고 있습니다. iPhone에서 앱을 실행할 때 셀의 기본 크기는 테이블보기의 "행 크기"에서 설정됩니다.

테이블 뷰의 "행 크기"를 변경하면 모든 셀의 크기가 변경됩니다. 하나의 셀에 대해서만 사용자 정의 크기를 원하므로 그렇게하고 싶지 않습니다. 문제에 대한 프로그래밍 솔루션이있는 많은 게시물을 보았지만 가능하다면 스토리 보드를 통해 게시하는 것을 선호합니다.

답변:


295

에서 다이나믹rowHeight jQuery과의 세트는 항상 개별 셀 'rowHeight에 우선합니다.

그러나에 정적 세포,rowHeight 개별 셀에 설정된 UITableView를 재정의 할 수 있습니다.

버그인지 확실하지 않으면 Apple이 의도적으로이 작업을 수행하고있을 수 있습니까?


36
정답 # 3, 특히이 답변은 Interface Builder / Storyboards에 적용되기 때문입니다. IB 에서 을 선택하면 크기 관리자 가 맨 위에 행 높이를 표시하고 ( "사용자 정의"확인란 사용) 전체 테이블보기 를 선택 하면 크기 관리자 가 맨 위에 행 높이를 표시합니다 ( "사용자 정의 없음" "이 경우). pixelfreak이 말했듯이 테이블 뷰 설정 만 동적 셀에 사용됩니다. (의도적인지 확실하지 않음)
Rhubarb

8
이 답변이 솔루션은 변경 간단하게 될 것이라고 의미 UITableView에서 내용을 Dynamic PrototypesStatic Cells, 그했다, 그리고 내 모든 프로젝트는 거의 자신을 살해 ... 폭발.
abbood at

4
이 번호를 검색하는 방법이 있습니까? 깊이 파고 드는 유일한 방법은 스토리 보드에 뛰어 들어 거기서 꺼내는 것입니까?
Biclops

테이블이 동적이기 때문에 분명히 버그가 아닙니다. 따라서 시스템이 각 셀을 어디에서 사용했는지 알 수 있습니까? 그리고 각 프로토 타입이 몇 번이나 사용됩니까?
Vincent Bernier

처음 에 테이블 뷰를 "정적 셀"로 설정 한 다음 "동적 프로토 타입"으로 변경 하면 문제가있는 것 같습니다 . rowHeight의 대리자 메서드조차 무시되는 문제가있었습니다. 먼저 스토리 보드 XML을 직접 편집하여 문제를 해결 한 다음 처음부터 동적 프로토 타입을 사용하여 스토리 보드 장면을 처음부터 다시 작성했습니다.
Eric Goldberg

84

UITableViewController를 사용하는 경우이 메소드를 구현하십시오.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

행의 기능에서 높이를 선택할 수 있습니다. 예를 들어

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

이 예에서 첫 번째 행 높이는 100 픽셀이고 다른 행은 60 픽셀입니다.

나는 이것이 당신을 도울 수 있기를 바랍니다.


2
Beber, 항상 두 가지를 모두 수행해야합니까 (사용자 정의를 선택하고 스토리 보드에서 행 높이 값을 편집하고 heightForRowAtIndexPath에 지정하십시오)?
marciokoko

이것에 관해 당신을 도울 수 있습니까? 동적 높이가있는 동적 셀이 필요하지만이 방법을 사용하면 모든 셀을 반환하는 것이 무엇이든 대신 사라집니다. iPhone 5를 제외하고 장치 가 예상대로 작동합니다. 이유를 이해할 수 있습니까?
Ostmeistro

34

동적 셀의 rowHeight경우 UITableView항상 설정되어 개별 셀의rowHeight .

이 동작은 버그입니다. 두 곳에서 UI를 관리해야 할 때마다 오류가 발생하기 쉽습니다. 예를 들어 스토리 보드에서 셀 크기를 변경하는 경우 셀 크기도 변경해야 heightForRowAtIndexPath:합니다. Apple이 버그를 수정할 때까지 현재 가장 좋은 해결 방법은 재정의하는 heightForRowAtIndexPath:것이지만 스토리 보드의 실제 프로토 타입 셀을 사용하여 마법의 숫자 대신 높이를 결정하십시오 . 예를 들면 다음과 같습니다.

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

그러면 프로토 타입 셀 높이에 대한 변경 사항이 런타임에 자동으로 선택되며 UI를 스토리 보드와 같은 한 곳에서만 관리하면됩니다.


2
캐싱을 포함한 전체 코드로 답변을 게시했습니다. 참조 stackoverflow.com/a/16881312/292166
JosephH

1
와우 와우! 나는 대답을 찬성했지만 깨어 라! 이 방법은 의견에서 @Brennan이 말한 것처럼 성능 저하뿐만 아니라 메모리 누수와 같은 각 reloadData에서 메모리 할당을 증가시킵니다! 위의 lensovet의 해결 방법을 사용해야합니다! 이 메모리 누수를 잡으려면 하루를 보내십시오!
skywinder

cell.bounds.size.height가 항상 0.0 반환하기 때문에, 신속한 작동하지 않습니다
킹 마법사

1
시스템이 tableView : heightForRowAtIndexPath 메소드를 호출 한 시점에 셀이 아직 존재하지 않습니다. 전달 된 indexPath를 사용하여 데이터 모델에 색인을 작성하고 어떤 유형의 셀을 사용할 것인지 확인한 다음 해당 셀의 높이를 계산하여 리턴 할 수 있습니다. 이를 통해 시스템은 셀을 작성하기 전에 테이블의 셀을 배치 할 수 있습니다.
King-Wizard

1
또한 자신의 cellForRowAtIndexPath 메소드를 호출해서는 안됩니다. 테이블 뷰에는 cellForRowAtIndexPath 메소드가 있는데,이 색인 경로는 화면에 현재 표시되어 있지만 해당 색인 경로에 연관된 셀이없는 경우 해당 색인 경로에 대한 셀을 리턴합니다.
King-Wizard

22

프로토 타입 셀을 사용하는 스토리 보드에서 작동하도록 다양한 답변 / 의견 힌트에 코드를 작성했습니다.

이 코드는 :

  • 스토리 보드의 명백한 장소 이외의 다른 곳에 셀 높이를 설정할 필요가 없습니다.
  • 성능상의 이유로 높이를 캐시
  • 공통 함수를 사용하여 중복 된 논리를 피하기 위해 인덱스 경로의 셀 식별자를 가져옵니다.

Answerbot, Brennan 및 lensovet에게 감사합니다.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>

나는 이것이 오래된 대답이라는 것을 알고 있지만 다른 사람 이이 결과로 스택 오버플로가 발생한다는 것을 알고 있습니까? 뷰가로드되면 UISectionRowData refreshWithSection : tableViewRowData : get tableView : heightForRowAtIndexPath : 호출 dequeueReusableCellWithIdentifier : 호출 [UISectionRowData ...]를 호출하므로 재귀 스택 오버플로가 발생합니다. 이 솔루션을 정말로 사용하고 싶었지만 iOS7에서는 작동하지 않는 것 같습니다.
sbaker

cell.bounds.size.height가 항상 0.0 반환하기 때문에, 신속한 작동하지 않습니다
킹 마법사

시스템이 tableView : heightForRowAtIndexPath 메소드를 호출 한 시점에 셀이 아직 존재하지 않습니다. 전달 된 indexPath를 사용하여 데이터 모델에 색인을 작성하고 어떤 유형의 셀을 사용할 것인지 확인한 다음 해당 셀의 높이를 계산하여 리턴 할 수 있습니다. 이를 통해 시스템은 셀을 작성하기 전에 테이블의 셀을 배치 할 수 있습니다.
King-Wizard

또한 자신의 cellForRowAtIndexPath 메소드를 호출해서는 안됩니다. 테이블 뷰에는 cellForRowAtIndexPath 메서드가 있는데,이 인덱스 경로는 화면에 현재 표시되어 있지만 해당 인덱스 경로에 연결된 셀이없는 경우 해당 인덱스 경로에 대한 셀을 반환합니다.
King-Wizard

@ snow-tiger 나는 이것을 신속하게 시도하지는 않았지만 귀하의 의견을 이해하지 못합니다. 나는 '[my] 자신의 cellForRowAtIndexPath 메소드를 호출하지 않으며, 의도하지 않은 것입니다. 또한 tableView : heightForRowAtIndexPath가 호출 될 때 셀이 존재하지 않는다는 것을 알고 있습니다.이 코드의 요점이며 dequeueReusableCellWithIdentifier를 사용하여 셀을 가져 오는 이유는 무엇입니까? 이 답변에 게시 된 코드가 작동합니다. 신속하게 진행되는 추가 사항이 있거나 신속 변환에 옳지 않은 것이 있거나이 질문 / 답변이 목표로하는 다른 문제를 해결하려고합니다.
JosephH

19

실제로 행 높이로 변경 해야하는 두 곳이 있습니다. 먼저 셀을 변경 한 다음 이제 테이블보기를 선택하고 크기 검사기를 확인하십시오.


크기 관리자 탭> 행 높이의 tableview (되지 cellview)>에서
이만 kazemayni

이 세부 사항을 잊을 때마다 견과류를 운전합니다. 스토리 보드를 사용할 때 셀을 조정해도 tableView가 자동으로 업데이트되지 않는 이유를 모르겠습니다!
스쿠터

11

나는 그것이 버그라고 생각한다.

유틸리티 관리자가 아닌 스토리 보드에서 직접 마우스 드래그하여 높이를 조정하십시오.

이 방법 으로이 문제를 해결했습니다.


10

swift를 사용하는 경우 다음과 같이 사용하십시오. 스토리 보드를 사용하여 행 높이를 선택하지 마십시오. 프로그래밍 방식으로 테이블 행 높이를 다음과 같이 설정하십시오.

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}

이것은 작동하지만 더 일반적으로 할 수 있습니다 :cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
Andy Chou

7

스토리 보드에서 UITableviewCell (UITableviewController-정적 셀)의 높이를 다음 줄의 도움을 받아 얻을 수 있습니다.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}

6

XML보기에서 스토리 보드를 열고 편집 rowHeight 원하는 요소 속성 .

프로토 타입 행에 대해 사용자 정의 rowHeight를 설정하려고 할 때 효과적이었습니다. 인스펙터를 통해 작동하지 않지만 XML을 통해 작동합니다.


1
마우스 오른쪽 버튼을 클릭하고 "다른 이름으로 열기"-> "소스 코드"를 선택했습니다. rowHeight는 이미 120으로 설정되었습니다. 스토리 보드에 버그가 있으며 사용자 정의 셀 높이를 무시한다고 생각합니다.
zirinisp

6

cellscustom을 사용하여 prototype을 사용한 height다음 . : 을 호출 cellForRowAtIndexPath:하고 반환 할 수 frame.height있습니다.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}

이 방법을 추가하면 효과가 좋았으며 이제 스토리 보드의 모든 사용자 지정 내용이 그대로 유지됩니다.
daspianist 2018 년

지금까지 최고의 솔루션
TheJeff

4

정적 행 높이를 설정하려면 다음과 같이 할 수 있습니다.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}

4

나는 최근에 이것과 씨름했다. 내 문제는 위에 게시 된 솔루션이었습니다.heightForRowAtIndexPath: 시뮬레이터에서 iOS 7.1에서 작동 방법을 이지만 iOS 8.1로 간단히 전환하여 결과를 완전히 망쳤습니다.

자체 크기 조정 셀에 대해 더 많이 읽기 시작했습니다 (iOS 8에서 도입, 여기 읽기 ). 사용이 UITableViewAutomaticDimensioniOS 8에서 도움 이 될 것임 이 분명했습니다. 나는 그 기술을 사용해 보았고 사용을 삭제했습니다 heightForRowAtIndexPath:. 이제 iOS 8에서 완벽하게 작동했습니다. 그러나 iOS 7은 그렇지 않았습니다. 내가 뭘 했어? heightForRowAtIndexPath:iOS 8이 아니라 iOS 7에 필요 했습니다.

여기에 @JosephH의 답변에서 빌린 내 솔루션 (간결하게 트리밍)이 있습니다.

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0")은 실제로 내가 사용하고있는 어딘가에있는 매크로 정의 세트에서 온 것입니다 (매우 도움이 됨). 그것들은 다음과 같이 정의됩니다 :

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

2

Swift 4를 사용하여 XCode 9에서 작업 할 때도 동일한 문제가 발생했습니다 .

셀 내부의 UI 요소에 대한 자동 레이아웃 추가 및 사용자 정의 셀 행 높이는 지정된대로 작동합니다.


1
안녕, 어떻게 했어?
Back Packer

셀 맨 아래에 제한 조건 세트를 추가하기 만하면됩니다.
Justin

이 작업을 수행하고 스토리 보드에서 셀 높이에 대해 "자동"을 선택하면 실행시 올바르게 표시되지만 스토리 보드에서 모든 높이를 44로 설정하려고합니다. 스토리 보드를 올바르게 표시하려면 어떻게해야합니까?
David

1

동적 셀의 경우 UITableView에 설정된 rowHeight는 항상 개별 셀의 rowHeight를 재정의합니다. 행 내부의 내용이 있으면 동적 높이를 계산하십시오.


0

내가 찾을 수있는 유일한 진정한 해결책은 이것입니다.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

이것은 작동하며 스토리 보드에 이미있는 논리를 복제하는 경우 끔찍한 스위치를 가질 수 없습니다. 성능에 대해서는 확실하지 않지만 도착하면 추측합니다.cellForRow: 이미 초기화 된 셀에 하면 빠르다고 생각합니다. 물론 여기에는 부수적 인 피해가있을 수 있지만 여기서는 잘 작동하는 것 같습니다.

나는 또한 이것을 여기에 게시했다 : https://devforums.apple.com/message/772464

편집 : Ortwin Gentz 는 TableView의 모든 셀뿐만 아니라 보이는 셀뿐만 아니라 heightForRowAtIndexPath:호출 될 것이라고 상기 시켰습니다 . 올바른 스크롤 막대를 표시하려면 iOS에서 전체 높이를 알아야하므로 논리적으로 들립니다. 이는 20 개의 Cell과 같은 작은 TableView에서는 문제가 없지만 1000 Cell TableView에서는 잊어 버리는 것을 의미합니다.

또한 XML의 이전 트릭 : 첫 번째 주석과 같습니다. 올바른 값이 이미있었습니다.


0

의견으로 추가되었지만 가시성에 대한 답변으로 게시 :

처음 에 테이블 뷰를 "정적 셀"로 설정 한 다음 "동적 프로토 타입"으로 변경 하면 문제가있는 것 같습니다 . 대리자 메서드조차 heightForRowAtIndexPath무시 되는 문제가있었습니다 . 먼저 스토리 보드 XML을 직접 편집하여 문제를 해결 한 다음 처음부터 동적 프로토 타입을 사용하여 스토리 보드 장면을 처음부터 다시 작성했습니다.


0

Interface Builder를 통해이 문제에 대한 해결책을 찾지 못했기 때문에 초기 질문에 Interface Builder를 통해 솔루션을 요청했지만 두 개의 동적 셀을 사용하여 Swift 의 문제에 대한 프로그래밍 솔루션을 게시하기로 결정했습니다 . 어쨌든 스택 오버플로 커뮤니티에 도움이 될 수 있다고 생각합니다.

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }

이것은 모두 훌륭하고 훌륭하지만 코드를 잘못 읽지 않는 한 마법 번호에 의존하고 동적 셀에 대해 IB에서 설정 한 모든 값을 완전히 무시하므로 OP의 질문에 대한 해결책은 아닙니다
Danny

0

또 다른 방법은 문서 개요로 이동하여 프로토 타입 셀이 중첩 된 테이블 뷰를 선택하는 것입니다. 그런 다음 Size Inspector에서 테이블 뷰 Row Height를 원하는 값으로 변경하고 Automatic 상자를 선택 취소하십시오.

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