1. ホーム
  2. ios

[解決済み] 動的なセル高を持つUITableViewのreloadData()は、飛び跳ねたスクロールを引き起こします。

2022-04-27 16:25:48

質問

これはよくある問題のような気がするのですが、何か共通の解決策があるのでしょうか?

基本的に、私のUITableViewは、各セルに対して動的なセルの高さを持っています。もし私がUITableViewの最上部でなく tableView.reloadData() スクロールアップするとカクカクします。

これは、データを再ロードしたため、スクロールアップする際に、UITableViewが可視化される各セルの高さを再計算していることが原因だと考えています。どうすればそれを軽減できるのか、あるいは特定のIndexPathからUITableViewの終わりまでしかデータを再ロードしないようにするにはどうすればいいでしょうか?

さらに、なんとか一番上までスクロールしても、下にスクロールして戻り、上にスクロールしても、ジャンプすることなく問題なくスクロールできるのです。これは、UITableViewCellの高さがすでに計算されていたためと思われます。

解決するには?

ジャンプを防ぐには、セルを読み込んだときの高さを保存し、正確な値を tableView:estimatedHeightForRowAtIndexPath :

スウィフト

var cellHeights = [IndexPath: CGFloat]()

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cellHeights[indexPath] = cell.frame.size.height
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeights[indexPath] ?? UITableView.automaticDimension
}

Objective Cです。

// declare cellHeightsDictionary
NSMutableDictionary *cellHeightsDictionary = @{}.mutableCopy;

// declare table dynamic row height and create correct constraints in cells
tableView.rowHeight = UITableViewAutomaticDimension;

// save height
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    [cellHeightsDictionary setObject:@(cell.frame.size.height) forKey:indexPath];
}

// give exact height value
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = [cellHeightsDictionary objectForKey:indexPath];
    if (height) return height.doubleValue;
    return UITableViewAutomaticDimension;
}