[ios] UITableView 동적 셀 높이는 일부 스크롤 후에 만 ​​수정됩니다.

나는이 UITableView사용자 정의로 UITableViewCell자동 레이아웃을 사용하여 스토리 보드에 정의. 셀에는 여러 줄이 있습니다 UILabels.

에서 UITableView셀 높이를 올바르게 계산 하는 것처럼 보이지만 처음 몇 셀의 경우 해당 높이가 레이블간에 제대로 나뉘 지 않습니다. 조금 스크롤하면 모든 것이 예상대로 작동합니다 (처음에 올바르지 않은 셀도 포함).

- (void)viewDidLoad {
    [super viewDidLoad]
    // ...
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
    // ...
    // Set label.text for variable length string.
    return cell;
}

내가 놓칠 수있는 것이 있는데, 이로 인해 자동 레이아웃이 처음 몇 번 작업을 수행 할 수 없습니까?

이 동작을 보여주는 샘플 프로젝트 를 만들었습니다 .

샘플 프로젝트 : 첫 번째로드시 샘플 프로젝트의 테이블 상단보기.
샘플 프로젝트 : 아래로 스크롤하고 위로 스크롤 한 후 동일한 셀.



답변

이것이 명확하게 문서화되었는지 여부는 모르지만 [cell layoutIfNeeded]셀을 반환하기 전에 추가하면 문제가 해결됩니다.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"];
    NSUInteger n1 = firstLabelWordCount[indexPath.row];
    NSUInteger n2 = secondLabelWordCount[indexPath.row];
    [cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2];

    [cell layoutIfNeeded]; // <- added

    return cell;
}


답변

이것은 다른 유사한 솔루션이 그렇지 않은 경우 저에게 효과적이었습니다.

override func didMoveToSuperview() {
    super.didMoveToSuperview()
    layoutIfNeeded()
}

AutoLayout과 UITableViewAutomaticDimension을 사용하는 방법에 매우 익숙하기 때문에 실제 버그처럼 보이지만 가끔이 문제가 발생합니다. 마침내 해결 방법으로 작동하는 것을 발견하게되어 기쁩니다.


답변

처음에보기 밖으로 스크롤 된 셀에는 추가 기능 [cell layoutIfNeeded]cellForRowAtIndexPath작동하지 않습니다.

또한 [cell setNeedsLayout].

특정 셀의 크기를 올바르게 조정하려면 여전히 특정 셀을보기로 스크롤해야합니다.

대부분의 개발자는이 성가신 경우를 제외하고는 Dynamic Type, AutoLayout 및 Self-Sizing Cell이 제대로 작동하므로 매우 실망 스럽습니다. 이 버그는 모든 “더 큰”테이블 뷰 컨트롤러에 영향을줍니다.


답변

내 프로젝트 중 하나에서 같은 경험을했습니다.

왜 발생합니까?

일부 장치에 대해 약간의 너비가있는 스토리 보드에서 디자인 된 셀. 예 : 400px. 예를 들어 라벨의 너비가 동일합니다. 스토리 보드에서로드 할 때 너비는 400px입니다.

여기에 문제가 있습니다.

tableView:heightForRowAtIndexPath: 셀 레이아웃 전에 호출됩니다.

그래서 레이블과 셀의 높이를 400px 너비로 계산했습니다. 하지만 화면이있는 기기 (예 : 320px)에서 실행합니다. 그리고이 자동 계산 된 높이는 올바르지 않습니다. 라벨을 수동으로
설정 layoutSubviewstableView:heightForRowAtIndexPath:후에도 셀이 발생 하기 때문에 도움이되지 않습니다.preferredMaxLayoutWidthlayoutSubviews

내 솔루션 :

1) 하위 클래스 UITableView및 재정의 dequeueReusableCellWithIdentifier:forIndexPath:. 셀 너비를 테이블 너비와 동일하게 설정하고 셀 레이아웃을 적용합니다.

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
    CGRect cellFrame = cell.frame;
    cellFrame.size.width = self.frame.size.width;
    cell.frame = cellFrame;
    [cell layoutIfNeeded];
    return cell;
}

2) 하위 클래스 UITableViewCell. preferredMaxLayoutWidth에서 레이블을 수동으로 설정 합니다 layoutSubviews. 또한 contentView셀 프레임 변경 후 자동으로 레이아웃되지 않기 때문에 수동 레이아웃이 필요합니다 (이유는 모르겠지만 그렇습니다)

- (void)layoutSubviews {
    [super layoutSubviews];
    [self.contentView layoutIfNeeded];
    self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width;
}


답변

비슷한 문제가 있습니다. 첫 번째로드에서 행 높이가 계산되지 않았지만 스크롤하거나 다른 화면으로 이동하면이 화면으로 돌아와 행이 계산됩니다. 첫 번째로드에서 내 항목은 인터넷에서로드되고 두 번째로드에서는 내 항목이 Core Data에서 먼저로드되고 인터넷에서 다시로드되며 인터넷에서 다시로드 할 때 행 높이가 계산되는 것을 확인했습니다. 그래서 segue 애니메이션 중에 tableView.reloadData ()가 호출되면 (푸시 및 현재 segue와 동일한 문제) 행 높이가 계산되지 않는다는 것을 알았습니다. 그래서 뷰 ​​초기화에서 tableview를 숨기고 사용자에게 추악한 영향을 미치지 않도록 활동 로더를 넣고 300ms 후에 tableView.reloadData를 호출하면 문제가 해결됩니다. UIKit 버그라고 생각하지만이 해결 방법이 트릭을 만듭니다.

항목로드 완료 핸들러에 논문 줄 (Swift 3.0)을 넣었습니다.

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: {
        self.tableView.isHidden = false
        self.loader.stopAnimating()
        self.tableView.reloadData()
    })

이것은 왜 어떤 사람들에게는 layoutSubviews에 reloadData를 넣어 문제를 해결하는지 설명합니다.


답변

위의 솔루션 중 어느 것도 저에게 효과가 없었습니다. 효과가 있었던 것은 마법의 레시피입니다. 다음 순서로 호출하십시오.

tableView.reloadData()
tableView.layoutIfNeeded()
tableView.beginUpdates()
tableView.endUpdates()

내 tableView 데이터는 웹 서비스에서 채워지며 연결의 콜백에서 위의 줄을 작성합니다.


답변

제 경우에는 셀이 처음 표시 될 때 UILabel의 마지막 줄이 잘 렸습니다. 그것은 꽤 무작위로 발생했으며 올바르게 크기를 조정하는 유일한 방법은 뷰에서 셀을 스크롤하고 다시 가져 오는 것입니다. 지금까지 표시된 모든 가능한 솔루션 (layoutIfNeeded..reloadData)을 시도했지만 아무것도 효과가 없었습니다. 트릭은 “Autoshrink”Minimuum Font Scale (저는 0.5) 로 설정하는 것이 었습니다 . 시도 해봐