Değiştirirken bir UITableView animasyonu için reloadData'ya sahip olun


183

İki modu olan bir UITableView var. Modlar arasında geçiş yaptığımızda bölüm başına farklı sayıda bölüm ve hücre var. İdeal olarak, masa büyüdüğünde veya küçüldüğünde harika bir animasyon yapar.

İşte denedim kodu, ama hiçbir şey yapmaz:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

Bunu nasıl yapabileceğim hakkında bir fikrin var mı?

Yanıtlar:


400

Aslında, çok basit:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

Gönderen belgeler :

Bu yöntemin çağrılması, tablo görünümünün veri kaynağından belirtilen bölümler için yeni hücreler istemesini sağlar. Tablo görünümü, eski hücreleri dışarıda canlandırırken yeni hücrelerin eklenmesini canlandırır.


13
Ve bu sayfadaki en iyi cevap!
Matthias D

41
Bu tamamen doğru değildir, çünkü yalnızca ilk bölümü yeniden yükleyecektir. Tablonuzda birden çok bölüm varsa, bu çalışmaz
Nosrettap

4
Hiçbir veri değişmediyse bir istisna yakalamanız mümkündür .. Cevabımı
Matej

8
@Nosrettap: tableView yeniden yüklemenizin daha fazla veya tüm bölümlerine sahip olmak istiyorsanız, yapmanız gereken tek şey NSIndexSet'inizi de yenilenmesi gereken tüm bölüm dizinleriyle genişletmektir
JonEasy

Hızlı sürüm: _tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Fade)Özellikle, yalnızca varsayılan ilk bölüm olan Bölüm 0'ı günceller.
kbpontius

264

Kullanmak isteyebilirsiniz:

Objective-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

hızlı

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

Hızlı 3, 4 ve 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

Sorun yok. : D

Daha UIViewAnimationOptionTransitionsserin efektler için istediğiniz herhangi birini de kullanabilirsiniz :

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

2
Bu, tablo görünümünüzün başlangıç ​​/ bitiş durumu çok farklıysa (ve eklemek / kaldırmak için bölümleri ve satırları hesaplamak karmaşıksa) yararlıdır, ancak animasyonlu olmayan yeniden yüklemenin daha az sarsıcı bir şeyi değerseniz.
Ben Packard

1
Bu, yerleşik yöntemleri kullanarak tablo görünümünü yeniden yüklemek kadar güzel bir animasyon değildir, ancak burada belirtilen daha yüksek puanlı yöntemin aksine, birden fazla bölümünüz olduğunda bu çalışır.
Mark Bridges

1
Vay canına tüm denedikten sonra bu benim için meydan okurcasına mükemmel
Lucas Goossen

1
@MarkBridges yüksek puanlı cevap birden çok bölümle çalışır :) -[_tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withRowAnimation:UITableViewRowAnimationFade];
lobianco

2
@Anthony Bitiş durumunun başlangıç ​​durumundan daha fazla / daha az bölümü varsa çalışmaz. Ardından, hangi bölümlerin eklendiğini / silindiğini manuel olarak izlemeniz gerekir, bu da oldukça zahmetlidir.
nikolovski

78

CATransitionSınıfı kullanma konusunda daha fazla özgürlüğe sahip olun .

Solma ile sınırlı değil, aynı zamanda hareketler de yapabilir.


Örneğin:

(içe aktarmayı unutmayın QuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

Vb. typeGibi ihtiyaçlarınıza göre değiştirin kCATransitionFade.

Swift'te uygulama:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

CATransition için referans

Hızlı 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

bu, tabloyu tek satırlar / bölümler yerine bir bütün olarak canlandırır.
Agos

@Agos Hala soruya cevap veriyor. "Yalnızca bir satırı yeniden yükleme" sorusunun, animasyonu layera özelliğine uygulamak gibi oldukça farklı bir yanıtı vardır UITableViewCell.
Matej

@matejkramny Tablonun sadece farklı satırları canlandırmasını bekledim (soruda belirtildiği gibi), ancak bu yöntem tüm tabloları aynı anda iter. Belki bir şey eksik?
Agos

@Agos hmm hayır bunu yapması gerekiyor. QuartzCore görünümü doğrudan değiştirdiği için tablonun sadece yarısını yapamaz. Hücreleri tablo görünümünden almayı ve sonra bu animasyonu her birine uygulamayı deneyebilirsiniz (ancak işe yarayacağından emin değilsiniz)
Matej

2
kCATransitionFade ile bir cazibe gibi çalıştı Teşekkürler! :)
quarezz

60

Veri yapınızı güncelleyebileceğinize inanıyorum, o zaman:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

Ayrıca, "withRowAnimation" tam olarak bir boole değil, bir animasyon stili:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

Basit şeyler, ancak StackOverflow'a doğrudan gitmek ve ihtiyacınız olan snippet'i trol dokümanlarından almak çok kolay. . Teşekkürler!
Jasper Blues

24

Bu yanıtların tümü, yalnızca 1 bölümlü bir UITableView kullandığınızı varsayar.

1'den fazla bölüm kullandığınız durumları doğru bir şekilde işlemek için:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(Not: 0'dan fazla bölümünüz olduğundan emin olmalısınız!)

Dikkat edilmesi gereken başka bir şey, veri kaynağınızı bu kodla aynı anda güncellemeye çalışırsanız bir NSInternalInconsistencyException ile karşılaşabileceğinizdir. Bu durumda, buna benzer bir mantık kullanabilirsiniz:

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

3
Bölüm hesaplamaları hakkında iyi bir nokta, ama sadece bir bölüm vardı ve kodunuz birer birer hata vardı. NSRange aralığı = NSMakeRange (0, myTableView.numberOfSections) kodunuzun ilk satırını değiştirmek zorunda kaldı;
Danyal Aytekin

18

Buna yaklaşmanın yolu, tableView öğesine satır ve bölümleri kaldırmasını ve eklemesini söylemektir

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation:Ve
deleteSections:withRowAnimation:

UITableView yöntemleri.

Bu yöntemleri çağırdığınızda, tablo istediğiniz öğeleri içeri / dışarı hareket ettirir, ardından bu animasyondan sonra durumu güncelleyebilmeniz için reloadData öğesini kendi başına çağırır. Bu bölüm önemlidir - her şeyi canlandırır ancak tablonun dataSource'u tarafından döndürülen verileri değiştirmezseniz, animasyon tamamlandıktan sonra satırlar tekrar görünür.

Yani, uygulama akışınız:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

Tablonuzun dataSource yöntemleri, denetleyerek [self tableIsInSecondState](veya herhangi bir şekilde) doğru yeni bölüm ve satır kümesini döndürdüğü sürece , bu, aradığınız efekti elde edecektir.


16

En iyi cevap hakkında yorum yapamam, ancak hızlı bir uygulama olurdu:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

reloadSections için ilk bağımsız değişkene güncellemek istediğiniz sayıda bölüm ekleyebilirsiniz.

Dokümanlardaki diğer animasyonlar: https://developer.apple.com/reference/uikit/uitableviewrowanimation

solma Eklenen veya silinen satır veya satırlar tablo görünümünün içine veya dışına kaybolur.

sağ Eklenen satır veya satırlar sağdan içeri doğru kayar; silinen satır veya satırlar sağa doğru kayar.

sol Eklenen satır veya satırlar soldan içeri doğru kayar; silinen satır veya satırlar sola doğru kayar.

üst Eklenen satır veya satırlar içeri kayar; silinen satır veya satırlar yukarı doğru kayar.

alt Eklenen satır veya satırlar alttan içeri doğru kayar; silinen satır veya satırlar aşağı doğru kayar.

case none Eklenen veya silinen satırlar varsayılan animasyonları kullanır.

Orta Tablo görünümü, eski ve yeni hücreleri, yaptıkları veya işgal edecekleri alanda ortalamayı korumaya çalışır. İPhone 3.2'de mevcut.

otomatik Tablo görünümü sizin için uygun bir animasyon stili seçer. (İOS 5.0'da tanıtıldı.)


1
Swift 4.2 için: self.tableView.reloadSections ([0], ile: UITableView.RowAnimation.fade)
19'da Reefwing

14

@ Dmarnel cevap için Swift 4 sürümü:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

9

Hızlı Uygulama:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

8

İçin Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

1

Benim durumumda, tablo görünümüne ("daha fazla sonuç göster" işlevselliği için) 10 satır daha eklemek istedim ve aşağıdakileri yaptım:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

Çoğu durumda, "self.numberOfRows" yerine, tablo görünümü için genellikle nesne dizisi sayısını kullanırsınız. Bu nedenle, bu çözümün sizin için iyi çalıştığından emin olmak için "arrayOfIndexPaths", eklenen satırların dizin yollarının doğru bir dizisi olmalıdır. Bu dizin yollarından herhangi biri için satır varsa, kod çökebilir, bu nedenle çökmeyi önlemek için bu dizin yollarında "reloadRowsAtIndexPaths: withRowAnimation:" yöntemini kullanmalısınız.


1

UITableView hücrelerine kendi özel animasyonlarınızı eklemek istiyorsanız şunu kullanın:

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

görünür hücre dizisi elde etmek için. Ardından her hücreye özel animasyon ekleyin.

Düzgün bir özel hücre animasyonu için gönderdiğim bu özü kontrol edin. https://gist.github.com/floprr/1b7a58e4a18449d962bd


1

Swift'te reloadData () olmadan animasyon yapmak şu şekilde yapılabilir (2.2 sürümünden itibaren):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

animasyon sona erdikten sonra reloadData () yöntemini çağırmanız gerekirse, CATransaction'daki değişiklikleri şu şekilde kucaklayabilirsiniz:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

Mantık, satırları sildiğiniz durumda gösterilir, ancak aynı fikir satır eklemek için de işe yarar. Animasyonu düzgün yapmak için UITableViewRowAnimation.Left olarak da değiştirebilir veya mevcut diğer animasyonlar listesinden seçim yapabilirsiniz.


1
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];

2
Süreyi neden .3iki kez ayarladınız ?
Pang

1

Yalnızca özel süreye sahip bölümleri değil, tüm bölümleri yeniden yüklemek için .

Özel süreyi ayarlamak için kullanıcı durationparametresi UIView.animate.

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

0

UITableViewSwift'te yerel animasyonlar

Aynı anda oluşmaları için satırları bir kerede ekleyin ve silin tableView.performBatchUpdates. @ İKenndac'ın cevabına dayanarak aşağıdaki yöntemleri kullanın:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

Ör:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

Bu, üstten yüklenen bir animasyonla sıfır konumuna bir bölüm ekler. Bu,cellForRowAt yöntemi ve o konumda yeni bir hücre olup olmadığını kontrol . Tüm tablo görünümünü bu şekilde belirli animasyonlarla yeniden yükleyebilirsiniz.

Re: OP soru, alternatif tablo görünüm durumu için hücreleri göstermek için bir koşullu bayrak gerekli olurdu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.