13

他の行とは高さが異なる UITableView の行の追加または削除をアニメーション化する際に問題が発生しています。

次の GIF は、デフォルトの高さ (44pts) の行とそれよりも大きな行 (100pts) の挿入および削除に関する問題を示しています。左側はシミュレーターの画面記録 (5 行目をカバーする新しいセルは別の問題です) で、右側はそれが何をすべきかのモックアップです。

アニメ号のgifどのように見えるべきかのgif

私の場合、それぞれの高さが 60pts の行がたくさんあります。セル内のボタンをタップすると、「編集」セルが下からスライドして下のセルを押し下げます。この編集セルの高さは 180 ポイントです。insertRowsAtIndexPaths:withRowAnimation:またはを呼び出すdeleteRowsAtIndexPaths:withRowAnimation:と、アニメーションは 180pts ではなく、60pts の間違った高さを前提とします。
これはUITableViewRowAnimationTop、新しいセルの場合、最終的な位置から -60pts に表示され、新しいセルにスライドすることを意味します。位置; 行うべきアニメーションの約 3 分の 1 です。一方、下の行は、開始位置から 180 ポイント下までスムーズにアニメーション化されています。

誰かがこれに対する実際の解決策を考え出しましたか? 新しい行にアニメーションの高さを伝える方法はありますか?

以下は、編集行を非表示および表示するために使用しているコードです。を使用しTLSwipeForOptionsCellて編集をトリガーしていますが、たとえばを使用して簡単に複製できますtableView:didSelectRowAtIndexPath:

-(void)hideEditFields{
    [self.tableView beginUpdates];

    [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
    editFormVisibleForRow = -1;

    [self.tableView endUpdates];
}

-(void)cellDidSelectMore:(TLSwipeForOptionsCell *)cell{
    NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
    // do nothing if this is the currently selected row
    if(editFormVisibleForRow != indexPath.row){
        if(editFormVisibleForRow >= 0){
            [self hideEditFields];
            // update the index path, as the cell positions (may) have changed
            indexPath = [self.tableView indexPathForCell:cell];
        }

        [self.tableView beginUpdates];

        editFormVisibleForRow = indexPath.row;
        [self.tableView insertRowsAtIndexPaths:@[
                                             [NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]
                                             ] withRowAnimation:UITableViewRowAnimationTop];

        [self.tableView endUpdates];
    }
}

-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _dataSource.count + (editFormVisibleForRow >= 0 ? 1 : 0);
}

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    int row = indexPath.row;
    if(editFormVisibleForRow >= 0 && row > editFormVisibleForRow && row <= editFormVisibleForRow + 1){
        return 180.0f;
    }
    else return 60.0;
}

少し調べてみると、これは明確な答えのない一般的な問題のようです。ここSOで見つけた同様の質問のほとんどは、回答されていないか、質問者の状況に固有の回避策を提供しています。(例: RowAnimation の問題カスタム UITableViewCell の高さが不適切なアニメーションを生成する、さまざまな高さのセルを削除および挿入するときの UITableView アニメーションの不具合)。

また、トリプルサイズの編集行を1つ作る代わりに、3つの小さな行を作成してアニメーション化しようとしましたが、これは一度にすべて表示されるため、適切ではありませんでした. また、それらを次々とアニメーション化しようとしましたが、編集ビュー全体が一度の動きでビューからスライドするのではなく、明らかな 3 ステップのアニメーションが発生して、イージングが奇妙に見えました。

編集:reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNoneアニメーション化しようとしている行の上の行を呼び出すと、アニメーションの動作が変わることに気付きました。つまり、次のアニメーションで示されているように、アニメーションは高さが 0pts であると想定しています。それは私が望むものに近いですが、アニメーションの速度が間違っていてギャップが残っているため、まだ正しくありません(私のアプリでは、これは背景色が突き抜けていることを意味します)

前の行がリロードされた問題の gif

4

2 に答える 2

0

解決策は非常に簡単です。の高さのセルを挿入し、0高さを予想されるサイズに変更してから と を呼び出す必要がbeginUpdatesありendUpdatesます。

ここにいくつかの擬似コードがあります。

var cellHeight: CGFloat = 0

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let dynamicHeightIndex = 2
    if indexPath.row == dynamicHeightIndex {
        return cellHeight
    } else {
        return tableView.rowHeight
    }
}

func insertCell() {
    // First update the data source before inserting the row
    tableView.insertRows(at: [someIndexPath], with: .none)

    cellHeight = 200

    tableView.beginUpdates()
    tableView.endUpdates()
}

セルを削除するには、テーブル ビューから削除する前に、更新アニメーションが完了するまで待つ必要があります。

iOS 11 にfunc performBatchUpdates(_:completion:)は、完了ブロックを提供する があります。CATransaction以前のバージョンでは、補完を使用して試すことができます。

cellHeight = 0

CATransaction.begin()
CATransaction.setCompletionBlock({
    self.tableView.deleteRows(at: [someIndexPath], with: .none)
})

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()
于 2018-03-27T12:01:31.950 に答える