Skąd mam wiedzieć, że UICollectionView został załadowany całkowicie?
Muszę wykonać jakąś operację za każdym razem, gdy UICollectionView zostanie całkowicie załadowany, tzn. w tym czasie powinny być wywołane wszystkie metody UICollectionView datasource / layout. Skąd mam to wiedzieć?? Czy jest jakaś metoda delegata, aby wiedzieć o załadowanym statusie UICollectionView?
20 answers
// In viewDidLoad
[self.collectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// You will get here when the reloadData finished
}
- (void)dealloc
{
[self.collectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-25 14:28:25
To mi pomogło:
[self.collectionView reloadData];
[self.collectionView performBatchUpdates:^{}
completion:^(BOOL finished) {
/// collection-view finished reload
}];
Swift 4 składnia:
self.collectionView.reloadData()
self.collectionView.performBatchUpdates(nil, completion: {
(result) in
// ready
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-09 21:24:53
To bardzo proste.
Na przykład wywołując metodę reloadData UICollectionView lub metodę invalidateLayout układu, wykonujesz następujące czynności:
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
dispatch_async(dispatch_get_main_queue(), ^{
//your stuff happens here
//after the reloadData/invalidateLayout finishes executing
});
Dlaczego to działa:
W głównym wątku (gdzie powinniśmy wykonywać wszystkie aktualizacje UI) znajduje się główna kolejka, która ma charakter seryjny, tzn. działa w trybie FIFO. Tak więc w powyższym przykładzie pierwszy blok zostanie wywołany, w którym zostanie wywołana nasza metoda reloadData
, a następnie cokolwiek innego w drugim bloku.
Teraz główny wątek również się blokuje. Więc jeśli wykonanie reloadData
zajmie 3s, przetwarzanie drugiego bloku zostanie odroczone o te 3s.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-06 05:31:38
Żeby dodać do świetnej @dezinezync odpowiedz:
Swift 3 +
collectionView.collectionViewLayout.invalidateLayout() // or reloadData()
DispatchQueue.main.async {
// your stuff here executing after collectionView has been layouted
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 18:43:43
Inne podejście przy użyciu RxSwift/RxCocoa:
collectionView.rx.observe(CGSize.self, "contentSize")
.subscribe(onNext: { size in
print(size as Any)
})
.disposed(by: disposeBag)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-02 09:28:27
Zrób to tak:
UIView.animateWithDuration(0.0, animations: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.collectionView.reloadData()
}, completion: { [weak self] (finished) in
guard let strongSelf = self else { return }
// Do whatever is needed, reload is finished here
// e.g. scrollToItemAtIndexPath
let newIndexPath = NSIndexPath(forItem: 1, inSection: 0)
strongSelf.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-10 11:03:52
Spróbuj wymusić Przejście układu synchronicznego przez layoutifneeded () zaraz po wywołaniu reloadData (). Wygląda na to, że działa zarówno dla UICollectionView, jak i UITableView na iOS 12.
collectionView.reloadData()
collectionView.layoutIfNeeded()
// cellForItem/sizeForItem calls should be complete
completion?()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-01 22:31:28
Jako odpowiedź dezinezync , musisz wysłać do kolejki głównej blok kodu po reloadData
z UITableView
lub UICollectionView
, a następnie ten blok zostanie wykonany po usunięciu komórek
Aby uczynić to bardziej prostym podczas używania, użyłbym rozszerzenia takiego jak:
extension UICollectionView {
func reloadData(_ completion: @escaping () -> Void) {
reloadData()
DispatchQueue.main.async { completion() }
}
}
Może być również zaimplementowany do UITableView
, jak również
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-03 03:33:31
Najlepszym rozwiązaniem, jakie do tej pory znalazłem, jest użycie CATransaction
w celu obsługi zakończenia.
Swift 5:
CATransaction.begin()
CATransaction.setCompletionBlock {
// UICollectionView is ready
}
collectionView.reloadData()
CATransaction.commit()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-16 07:32:45
Wykonałem następujące czynności, aby wykonać cokolwiek po przeładowaniu widoku kolekcji. Możesz użyć tego kodu nawet w odpowiedzi API.
self.collectionView.reloadData()
DispatchQueue.main.async {
// Do Task after collection view is reloaded
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-04 09:53:32
To działa dla mnie:
__weak typeof(self) wself= self;
[self.contentCollectionView performBatchUpdates:^{
[wself.contentCollectionView reloadData];
} completion:^(BOOL finished) {
[wself pageViewCurrentIndexDidChanged:self.contentCollectionView];
}];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-12 03:18:06
Musiałem wykonać jakąś akcję na wszystkich widocznych komórkach, gdy widok kolekcji zostanie załadowany, zanim będzie widoczny dla użytkownika, użyłem:
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if shouldPerformBatch {
self.collectionView.performBatchUpdates(nil) { completed in
self.modifyVisibleCells()
}
}
}
Zwróć uwagę, że zostanie to wywołane podczas przewijania widoku kolekcji, więc aby temu zapobiec, dodałem:
private var souldPerformAction: Bool = true
I w samej akcji:
private func modifyVisibleCells() {
if self.shouldPerformAction {
// perform action
...
...
}
self.shouldPerformAction = false
}
Akcja nadal będzie wykonywana wielokrotnie, jako liczba widocznych komórek w stanie początkowym. ale na wszystkich tych połączeniach będziesz miał ta sama liczba widocznych komórek (wszystkie). Flaga logiczna uniemożliwi jej ponowne uruchomienie po rozpoczęciu przez użytkownika interakcji z widokiem kolekcji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-06 13:15:00
Po prostu przeładuj collectionView wewnątrz aktualizacji wsadowych, a następnie sprawdź w bloku zakończeń, czy jest zakończona, czy nie za pomocą boolean "finish".
self.collectionView.performBatchUpdates({
self.collectionView.reloadData()
}) { (finish) in
if finish{
// Do your stuff here!
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-06 18:54:54
SWIFT 5
override func viewDidLoad() {
super.viewDidLoad()
// "collectionViewDidLoad" for transitioning from product's cartView to it's cell in that view
self.collectionView?.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let observedObject = object as? UICollectionView, observedObject == self.collectionView {
print("collectionViewDidLoad")
self.collectionView?.removeObserver(self, forKeyPath: "contentSize")
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-04 11:55:18
Def do this:
//Subclass UICollectionView
class MyCollectionView: UICollectionView {
//Store a completion block as a property
var completion: (() -> Void)?
//Make a custom funciton to reload data with a completion handle
func reloadData(completion: @escaping() -> Void) {
//Set the completion handle to the stored property
self.completion = completion
//Call super
super.reloadData()
}
//Override layoutSubviews
override func layoutSubviews() {
//Call super
super.layoutSubviews()
//Call the completion
self.completion?()
//Set the completion to nil so it is reset and doesn't keep gettign called
self.completion = nil
}
}
Następnie zadzwoń w ten sposób w swoim VC
let collection = MyCollectionView()
self.collection.reloadData(completion: {
})
Upewnij się, że używasz podklasy!!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 23:02:37
Ta praca dla mnie:
- (void)viewDidLoad {
[super viewDidLoad];
int ScrollToIndex = 4;
[self.UICollectionView performBatchUpdates:^{}
completion:^(BOOL finished) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:ScrollToIndex inSection:0];
[self.UICollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-23 08:16:19
Poniżej jest jedynym podejściem, które działało dla mnie.
extension UICollectionView {
func reloadData(_ completion: (() -> Void)? = nil) {
reloadData()
guard let completion = completion else { return }
layoutIfNeeded()
completion()
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-16 07:07:55
Tak rozwiązałem problem z Swift 3.0:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !self.collectionView.visibleCells.isEmpty {
// stuff
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 10:04:41
Spróbuj tego:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _Items.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
//Some cell stuff here...
if(indexPath.row == _Items.count-1){
//THIS IS THE LAST CELL, SO TABLE IS LOADED! DO STUFF!
}
return cell;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 04:43:41
Możesz zrobić tak...
- (void)reloadMyCollectionView{
[myCollectionView reload];
[self performSelector:@selector(myStuff) withObject:nil afterDelay:0.0];
}
- (void)myStuff{
// Do your stuff here. This will method will get called once your collection view get loaded.
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 07:19:01