2017-11-29 5 views
0

テーブルビューにアニメーションを追加して、読み込み時に見栄えを良くしました。コントローラのviewDidLoadでは、データの非同期要求が行われ、返されたときにテーブルビューが設定されます。既に表示されているUITableViewセルをアニメーション化しないでください。

テーブルがロードされると、セルが1つずつ表示されます。 (I took inspiration from this excellent guide)

- (void)tableFadeInAnimation { 
    //[_venueTableView reloadData]; 

    NSArray<UITableViewCell *> *cells = _venueTableView.visibleCells; 

    NSInteger index = 0; 

    for (UITableViewCell * m in cells){ 
     UITableViewCell *cell = m; 
     cell.alpha = 0; 
     [UIView animateWithDuration:1 delay:0.25 * index options:0 animations:^(){ 
      cell.alpha = 1; 
     } completion:nil]; 
     NSLog(@"end of table animation"); 
     index += 1; 
    } 
} 

これを初期化関数として実行した場合の問題は、これが完了してもテーブルに実行するアニメーションがなくなることです。私はこの原則をcellForRowAtIndexPath(ループを削除する)にしました。

cell.alpha = 0; 
[UIView animateWithDuration:2.0 animations:^(){ 
     cell.alpha = 1; 
    }]; 

これは、すべてのセルをまとめてロードしますが、テーブルに表示される新しいセルをアニメーション化します。

cell.alpha = 0; 

[UIView animateWithDuration:1 delay:0.05 * indexPath.row options:0 animations:^(){ 
    cell.alpha = 1; 
} completion:^(BOOL finished){ 
    NSLog(@"animation complete"); 
}]; 

これは、しかし、それはすべてのセル(見えないもの)に結びついているので、さらにあなたは、セルの長いロード時間をテーブルを下る1により各セル1表のロードを行いました。

また、テーブルをバックアップすると、すべての古いセルがテーブルに再現されます。私は古い細胞を残し、新しい細胞をアニメーション化したい。どの細胞がロードされたかを追跡して、まったく新しい細胞をアニメーション化する方法はありますか?

答えて

1

表示されている最後のセルのインデックス(名前lastCellDisplayedIndex)を保持するプロパティが必要です。インデックスがlastCellDisplayedIndex未満のセルのみをアニメートします。 reloadDataを呼び出すたびに、lastCellDisplayedIndex = -1をリセットします。

下記のコードを試してください。

@property (nonatomic, assign) NSUInteger lastCellDisplayed; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self reloadTableView]; 
} 

// Use this method each time you want to reload data of tableView 
// instead of |reloadData| method 
- (void)reloadTableView { 
    _lastCellDisplayedIndex = -1; 
    [self.tableView reloadData]; 
} 

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 
    // Update |_lastCellDisplayedIndex| each time a cell is displayed 
    _lastCellDisplayedIndex = MAX(indexPath.row, _lastCellDisplayedIndex); 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    ... 
    // Only animate cells which have |indexPath.row| < |_lastCellDisplayedIndex| 
    if (_lastCellDisplayedIndex < indexPath.row) { 
    cell.alpha = 0; 

    [UIView animateWithDuration:1 delay:0.05 * indexPath.row options:0 animations:^(){ 
     cell.alpha = 1; 
    } completion:^(BOOL finished){ 
     NSLog(@"animation complete"); 
    }]; 
    } else { 
    cell.alpha = 1; 
    } 
    ... 
} 
0

このための最良のアプローチは、あなたには、いくつかのバッキング・データ・ソースを持っていると仮定すると、あなたのUITableViewDelegate

+0

'willDisplayCell'は、再利用されたセルに対して呼び出されます。同じ問題。 – Connor

+0

@Connorこれは正しいです。私は実際に 'willDisplayCell'を試してみましたが、' cellForIndexPath'のコードを持っているのと同じように動作しました。 – Axemasta

+0

@Axemasta私の答えはどうですか; – trungduc

0

私の推奨されるアプローチのtableView:willDisplayCell:forRowAtIndexPath:方法では、あなたのセルの枠やアルファにあなたのアニメーションブロックと任意の変更を追加することですcellForRowAtIndexPathにデータを提供するには、モデルオブジェクトにいくつかの変更可能なプロパティーhasBeenDisplayedを追加します(または、各モデルオブジェクトを表示されているかどうかを示すブールにマップするNSDictionary)。このロジックは複雑で、ビューコードの一貫性を保証するロジックコードが必要です。次に、このプロパティを取得したら、セルがまだ表示されていない場合はcellForRowAtIndexPathにカスタムアニメーションを呼び出すことができます。

+0

はい、私はこのアイデアを持ち、実装を開始しました。私は主にこの質問をして、リンゴが私にこれをする方法を提供しているかどうかを見てみました(私が素敵で怠け者になれるように)。私はおそらく 'hasBeenDiaplayed'データをローカルに保存しています。異なる目的で同じテーブルビューを使用しています。 – Axemasta

0

答えのための@trungducのおかげで、私は人々がそれが有用であることを期待して、これに完成した解決策を投稿しています。すでに表示されている表の描画セルを停止するには、テーブルに表示されている最大のインデックスであるlastCellDisplayedIndexを追跡する変数を実装する必要があります。 @ trungducの答えでは、彼は- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPathメソッドにこの変数を入れましたが、これによっていくつかのセルが再描画されるいくつかのエラーが発生することがわかりました。私はcellForRowcellWillDisplayメソッドの違いを読んでいました。アニメーションを配置するのに最適な場所のようでした。cellWillDisplayはセルが初期化されていて、明らかに、UIの操作をアニメーション!)。

このメソッドは、次のようになります。

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{ 

    lastCellDisplayedIndex = MAX(indexPath.row, lastCellDisplayedIndex); 
    NSLog(@"lastCellDisplayedIndex = %ld, indexPath for Cell = %ld", lastCellDisplayedIndex, indexPath.row); 

    if (lastCellDisplayedIndex <= indexPath.row){ 
     cell.alpha = 0; 
     [UIView animateWithDuration:2.0 animations:^(){ 
      cell.alpha = 1; 
     }]; 
     if (lastCellDisplayedIndex == totalCellsToDisplay - 1){ 
      NSLog(@"END OF TABLE ANIMATIONS!"); 
      lastCellDisplayedIndex = totalCellsToDisplay + 1; 
     } 
    } 
    else { 
     cell.alpha = 1; 
    } 

} 

この方法では、ほとんどすべてを処理します。最初にlastCellDisplayedIndexの値を、テーブルが見た最大インデックスの値に変更します。次に、処理しているセルをアニメートするか、そのまま放置するかを決定します。私はまた、totalCellsToDisplayがあなたのテーブルのデータソース配列として作用する、(種類の)ガード変数を追加する必要がありました: -

(NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return totalCellsToDisplay; 
} 

は、だからあなたの本当のアプリであなたの代わりに私が

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return yourTableDataArray.count; 
} 

理由を持っているでしょうあなたはこのコードを持っている場合、描画されているセルの最大数は、チェック:

lastCellDisplayedIndex = MAX(indexPath.row, lastCellDisplayedIndex); 

if (lastCellDisplayedIndex <= indexPath.row){} 

、最大のインデックスは、最終的な細胞よりも高い行くことは決してありませんので、この細胞は、すべてのタイムを生き返らされますあなたは上下にスクロールします。 indexPath = the total cells - 1(ゼロインデックスのため)を修正するには、lastCellDisplayedIndexの値をバンプして、それ以上のセルが描画されないようにします。

最後に、テーブルが最初に描画するセルの数を解決する必要があります。私はこれがどういう仕組みかはっきりしていませんが、私のテストでは15個以上のセルが返されます(15個を返した場合)。とにかく私はずば抜けたロードアニメーションを実装し、アニメーション機能をロードすることでこの問題を解決しました。

- (void)tableFadeInAnimation { 
    [_myTable reloadData]; 

    NSArray<UITableViewCell *> *cells = _myTable.visibleCells; 

    NSInteger index = 0; 

    for (UITableViewCell * m in cells){ 
     UITableViewCell *cell = m; 
     cell.alpha = 0; 
     [UIView animateWithDuration:0.5 delay:0.25 * index options:0 animations:^(){ 
      cell.alpha = 1; 
     } completion:^(BOOL finished){ 
      lastCellDisplayedIndex = _myTable.visibleCells.count; 
      NSLog(@"Table Animation Finished, lastCellDisplayed Index = %ld", lastCellDisplayedIndex); 
     }]; 
     NSLog(@"end of table animation"); 
     index += 1; 
    } 
} 

Iが表示されている細胞の数に等しいlastCellDisplayedの値を設定する機能の完了ブロックを使用します。これで、テーブルビューはすべての新しいセルをアニメーション化します。

これは役に立っています。回答は@trungducにお寄せください!

関連する問題