128

自動レイアウトを使用してストーリーボードで定義され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;
}

最初の数回、自動レイアウトが機能しない原因となっているものはありますか?

この動作を示すサンプル プロジェクトを作成しました。

サンプル プロジェクト: 最初の読み込み時のサンプル プロジェクトのテーブル ビューの上部。 サンプル プロジェクト: 下にスクロールして上に戻った後の同じセル。

4

29 に答える 29

151

これが明確に文書化されているかどうかはわかりませんが、[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;
}
于 2014-09-22T09:58:36.183 に答える
14

私は自分のプロジェクトの1つで同じ経験をしました。

なぜそれが起こるのですか?

ストーリーボードで設計された、一部のデバイス用の幅を持つセル。たとえば、400 ピクセル。たとえば、ラベルの幅は同じです。ストーリーボードから読み込むと、幅は 400px になります。

ここに問題があります:

tableView:heightForRowAtIndexPath:サブビューのセルレイアウトの前に呼び出されます。

したがって、幅400pxのラベルとセルの高さを計算しました。ただし、画面付きのデバイス (320px など) で実行します。そして、この自動計算された高さは正しくありません。セルが後でのlayoutSubviewsみ発生するという理由だけで、ラベルを手動でtableView: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) サブクラスUITableViewCellpreferredMaxLayoutWidthでラベルを手動で設定しますlayoutSubviews。また、セルフレームの変更後に自動的にレイアウトされないため、手動でレイアウトする必要がありますcontentView(理由はわかりませんが、そうです)

- (void)layoutSubviews {
    [super layoutSubviews];
    [self.contentView layoutIfNeeded];
    self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width;
}
于 2015-09-28T21:54:47.137 に答える
10

私は同様の問題を抱えています。最初のロードでは、行の高さは計算されませんでしたが、スクロールした後、または別の画面に移動すると、この画面に戻って行が計算されます。最初の読み込みでアイテムがインターネットから読み込まれ、2 回目の読み込みでアイテムが最初に Core Data から読み込まれ、インターネットからリロードされます。インターネットからのリロードで行の高さが計算されることに気付きました。そのため、セグエアニメーション中に tableView.reloadData() が呼び出されると (プッシュと現在のセグエと同じ問題)、行の高さが計算されないことに気付きました。したがって、ビューの初期化時にテーブルビューを非表示にし、アクティビティローダーを配置してユーザーへの醜い影響を防ぎ、300ミリ秒後に tableView.reloadData を呼び出すと、問題は解決しました。UIKitのバグだと思いますが、この回避策でうまくいきます。

これらの行(Swift 3.0)をアイテムロード完了ハンドラーに入れました

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

これは、一部の人々にとって、reloadDataをlayoutSubviewsに配置して問題を解決する理由を説明しています

于 2016-12-26T21:11:00.120 に答える
5

私の場合、セルが初めて表示されたときに UILabel の最後の行が切り捨てられました。それはかなりランダムに発生し、正しいサイズにする唯一の方法は、セルをビューからスクロールして元に戻すことでした。これまでに表示されたすべての解決策(layoutIfNeeded..reloadData)を試しましたが、何もうまくいきませんでした。トリックは、「自動縮小」最小フォントスケール(私にとっては0.5)に設定することでした。試してみる

于 2015-05-01T13:36:38.217 に答える
3

私の場合、設定preferredMaxLayoutWidthが役立ちます。追加した

cell.detailLabel.preferredMaxLayoutWidth = cell.frame.width

私のコードで。

UILabelhttp://openradar.appspot.com/17799811で 1 行のテキストが 2 行になるも参照してください。

于 2015-06-09T00:32:41.940 に答える
1

ラベルのサイズ変更に問題があるため
、テキストを設定した後に chatTextLabel.text = chatMessage.message chatTextLabel?.updateConstraints()を実行するだけで済みます

// 完全なコード

func setContent() {
    chatTextLabel.text = chatMessage.message
    chatTextLabel?.updateConstraints()

    let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0
    let labelTextHeight = chatTextLabel?.intrinsicContentSize().height

    guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else {
      trailingConstraint?.constant = trailingConstant
      return
    }
    trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth)

  }
于 2016-05-20T13:54:41.043 に答える
0

私の場合、セルの高さの問題は、最初のテーブル ビューが読み込まれた後に発生し、ユーザー アクションが発生します (セルの高さを変更する効果のあるセルのボタンをタップします)。私がしない限り、セルの高さを変更することができませんでした:

[self.tableView reloadData];

私は試しました

[cell layoutIfNeeded];

しかし、それはうまくいきませんでした。

于 2016-11-04T20:23:05.887 に答える
0

iOS 11+

テーブル ビューは、デフォルトで推定高さを使用します。これは、contentSize が当初の推定値と同じであることを意味します。contentSize を使用する必要がある場合は、推定高さの 3 つのプロパティをゼロに設定して、推定高さを無効にする必要があります。

    public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
        return CGFloat.leastNormalMagnitude
    }
于 2021-03-03T16:58:07.907 に答える