web-dev-qa-db-ja.com

UIRefreshControl endRefreshingがスムーズでない

データの読み込みが完了し、tableViewが再読み込みされたら、更新コントロールでendRefreshingを呼び出し、読み込み状態から「ジャンプ」して非表示にします。更新コントロールが完了したときにスライドして滑らかなアニメーションを実行する方法を教えてください。 ?

22
Halpo

説明が正確ではないので、新しい答えを追加します。そして、これはおそらくコメントには多すぎるでしょう。

Halpo による解は正しいです。しかし、言及された理由は間違っています。

-[NSObject (NSDelayedPerforming) performSelector:withObject:afterDelay:]を呼び出すと、呼び出しが次のrunloop反復で実行されることが保証されます。

したがって、少し遅延があるため、これは機能しませんが、次のループに移動しています。

実際には、遅延を0.0に減らすことができますが、それでも機能します。また、より正確な(結果の改善ではなく、何かを達成するためのオブジェクトの使用に関して)実装が可能です。

そのためのさまざまなコードスニペットを次に示します。

// SOLUTION I

[[self tableView] reloadData];
[[self refreshControl] performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.0];

// SOLUTION II (semantically correct)

[[self tableView] reloadData];
[[NSOperationQueue currentQueue] addOperationWithBlock:^{
    [[self refreshControl] endRefreshing];
}];

// SOLUTION III (GCD)

dispatch_async(dispatch_get_main_queue(), ^{
    [[self refreshControl] endRefreshing];
}];

[〜#〜]編集[〜#〜]

johann-fradj が指摘したように、GCDを使用することもできます。私はGCDが大好きですが、ソリューションIIは何が起こっているかを最もよく説明しています。また、GCDはあまりObjective-C風ではないので、個人的には自分の解決策に固執したいと思います。

27

問題を修正しました-データを再ロードした後、endRefreshに小さな遅延を追加しました:

[self.tableView reloadData];
[self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.05];
26
Halpo

Swift 4ソリューション

    tableView.reloadData()
    if refreshControl?.isRefreshing == true {
        DispatchQueue.main.async {
            self.refreshControl?.endRefreshing()
        }
    }

その他のソリューション(遅延、CATransactionの使用など)はより複雑であり、目に見える利点はありません

4
coldfire

endRefreshing()の呼び出しをUIViewアニメーションブロックにラップしてみてください。

私もこの問題に遭遇しました。 endRefreshing()の場合、ドキュメントには次のように記載されています。

UIView.animateWithDuration(0.5) {
    self.refreshControl.endRefreshing()
}

ドキュメントは述べています:

アニメーションも有効な場合、コントロールはアニメーションを使用して非表示になります。

2
Eytan

理由の1つは、endRefreshが呼び出された後にテーブルビューを更新することです。たとえば、私の呼び出しは次のようになりました:

[self.refreshControl beginRefreshing];
[self.network getThings:^(id things, NSError *error) {
    [self.refreshControl endRefreshing];

    if (error) {
        ...
    } else {
        self.things = things;
        [self.tableView reloadData];
    }
}];

EndRefreshアニメーションの実行中にテーブルが自動的に更新されるため、これは悪いことです。したがって、正しく行われたコードは次のようになります。

[self.refreshControl beginRefreshing];
[self.network getThings:^(id things, NSError *error) {
    if (error) {
        [self.refreshControl endRefreshing];
        ...
    } else {
        self.things = things;
        [self.tableView reloadData];
        [self.refreshControl endRefreshing];
    }
}];
0
gklka

私にとっての解決策は、refreshControl?.endRefreshing()beforetableView.reloadData()への呼び出しを実行することでした:

_refreshControl?.endRefreshing()
tableView.reloadData()
_

endRefreshing()の呼び出しがreloadData()の呼び出しの後だった場合、データが再ロードされるたびにTableViewがジャンプしました。

0
Forest Katsch