Widok tabeli animacja ładowania komórek jeden po drugim
Muszę animować Ładowanie wierszy widoku tabeli. Kiedy tabela przeładowuje dane potrzebuję wiersze dostać się z lewej jeden po drugim. Jak mogę to osiągnąć?
7 answers
W delegacie tableview,
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Umieść tę animację tłumaczenia od dołu do góry (uproszczoną z Anbu.Karthik odpowiedz),
//1. Define the initial state (Before the animation)
cell.transform = CGAffineTransformMakeTranslation(0.f, CELL_HEIGHT);
cell.layer.shadowColor = [[UIColor blackColor]CGColor];
cell.layer.shadowOffset = CGSizeMake(10, 10);
cell.alpha = 0;
//2. Define the final state (After the animation) and commit the animation
[UIView beginAnimations:@"rotation" context:NULL];
[UIView setAnimationDuration:0.5];
cell.transform = CGAffineTransformMakeTranslation(0.f, 0);
cell.alpha = 1;
cell.layer.shadowOffset = CGSizeMake(0, 0);
[UIView commitAnimations];
Dla lepszego UX, zaleca się, aby animacja była odtwarzana tylko raz dla każdego wiersza, dopóki widok tabeli nie zostanie zmniejszony.
Wstaw powyższy kod w
if (![self.shownIndexes containsObject:indexPath]) {
[self.shownIndexes addObject:indexPath];
// Your animation code here.
}
------- Swift -----------------------------------------------------------------------------------------------------------------
var shownIndexes : [IndexPath] = []
let CELL_HEIGHT : CGFloat = 40
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if (shownIndexes.contains(indexPath) == false) {
shownIndexes.append(indexPath)
cell.transform = CGAffineTransform(translationX: 0, y: CELL_HEIGHT)
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 10, height: 10)
cell.alpha = 0
UIView.beginAnimations("rotation", context: nil)
UIView.setAnimationDuration(0.5)
cell.transform = CGAffineTransform(translationX: 0, y: 0)
cell.alpha = 1
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
UIView.commitAnimations()
}
}
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-01-30 03:28:05
Swift 4
Add this little cute extension
extension UITableView {
func reloadWithAnimation() {
self.reloadData()
let tableViewHeight = self.bounds.size.height
let cells = self.visibleCells
var delayCounter = 0
for cell in cells {
cell.transform = CGAffineTransform(translationX: 0, y: tableViewHeight)
}
for cell in cells {
UIView.animate(withDuration: 1.6, delay: 0.08 * Double(delayCounter),usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
cell.transform = CGAffineTransform.identity
}, completion: nil)
delayCounter += 1
}
}
}
Wtedy zamiast " tableView.reloadData ()", użyj " tableView.reloadWithAnimation () "
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-10-28 14:01:14
Oto moje rozwiązanie Swift 3 do wyświetlania komórek jeden po drugim. co jest miłe w tym, że ładują się tylko przy pierwszym ładowaniu i tylko dla początkowo wyświetlanych komórek (nie będą działać, gdy użytkownik przewija się w dół).
Enjoy:)
private var finishedLoadingInitialTableCells = false
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
var lastInitialDisplayableCell = false
//change flag as soon as last displayable cell is being loaded (which will mean table has initially loaded)
if yourTableData.count > 0 && !finishedLoadingInitialTableCells {
if let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows,
let lastIndexPath = indexPathsForVisibleRows.last, lastIndexPath.row == indexPath.row {
lastInitialDisplayableCell = true
}
}
if !finishedLoadingInitialTableCells {
if lastInitialDisplayableCell {
finishedLoadingInitialTableCells = true
}
//animates the cell as it is being displayed for the first time
cell.transform = CGAffineTransform(translationX: 0, y: self.rowHeight/2)
cell.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0.05*Double(indexPath.row), options: [.curveEaseInOut], animations: {
cell.transform = CGAffineTransform(translationX: 0, y: 0)
cell.alpha = 1
}, completion: nil)
}
}
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-10-25 09:02:10
Żadne z dostarczonych rozwiązań mi nie pomogło, więc wymyśliłem własne. Oto mała klasa ogólnego przeznaczenia, którą można wykorzystać do łączenia animacji i odtwarzania ich jedna po drugiej. Jego składnia jest podobna do składni UIView.animate() i po wywołaniu, asynchronicznie kolejkuje animację, a następnie rozpoczyna wykonywanie kolejki sekwencyjnie w kolejności, w jakiej została dodana:
Swift 4.1
ChainedAnimationsQueue.swift
import UIKit
import Foundation
class ChainedAnimationsQueue {
private var playing = false
private var animations = [(TimeInterval, () -> Void, () -> Void)]()
init() {
}
/// Queue the animated changes to one or more views using the specified duration and an initialization block.
///
/// - Parameters:
/// - duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them.
/// - initializations: A block object containing the changes to commit to the views to set their initial state. This block takes no parameters and has no return value. This parameter must not be NULL.
/// - animations: A block object containing the changes to commit to the views. This is where you programmatically change any animatable properties of the views in your view hierarchy. This block takes no parameters and has no return value. This parameter must not be NULL.
func queue(withDuration duration: TimeInterval, initializations: @escaping () -> Void, animations: @escaping () -> Void) {
self.animations.append((duration, initializations, animations))
if !playing {
playing = true
DispatchQueue.main.async {
self.next()
}
}
}
private func next() {
if animations.count > 0 {
let animation = animations.removeFirst()
animation.1()
UIView.animate(withDuration: animation.0, animations: animation.2, completion: { finished in
self.next()
})
} else {
playing = false
}
}
}
Przykładowe Użycie:
var animationsQueue = ChainedAnimationsQueue()
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.alpha = 0.0
animationsQueue.queue(withDuration: 0.2, initializations: {
cell.layer.transform = CATransform3DTranslate(CATransform3DIdentity, cell.frame.size.width, 0, 0)
}, animations: {
cell.alpha = 1.0
cell.layer.transform = CATransform3DIdentity
})
}
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-07-27 16:28:36
Swift 4
Zrobiłem szybkie rozszerzenie na UITableView do animowania komórek:
tableView.reloadData() // To make sure tableView.visibleCells is not empty
tableView.animateCells(
cells: tableView.visibleCells,
duration: 0.3,
delay: 0.5,
dampingRatio: 0.8,
configure: { cell -> (prepare: () -> Void, animate: () -> Void)? in
guard let customCell = cell as? CustomCell else { return nil }
let preparations = {
customCell.iconImageView.alpha = 0
}
let animations = {
customCell.iconImageView.alpha = 1
}
return (preparations, animations)
}, completion: {
print("Cell animations are completed")
})
Rozszerzenie wygląda tak:
extension UITableView {
func animateCells<Cell: UITableViewCell>(cells: [Cell],
duration: TimeInterval,
delay: TimeInterval = 0,
dampingRatio: CGFloat = 0,
configure: @escaping (Cell) -> (prepare: () -> Void, animate: () -> Void)?,
completion: @escaping () -> Void) {
var cellDelay: TimeInterval = 0
var completionCount: Int = 0
for cell in cells {
if let callbacks = configure(cell) {
callbacks.prepare()
let animator = UIViewPropertyAnimator(duration: duration, dampingRatio: dampingRatio)
animator.addAnimations(callbacks.animate)
let completionTime = cellDelay + (duration * TimeInterval(dampingRatio))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + completionTime) {
completionCount += 1
if completionCount == cells.count {
completion()
}
}
animator.startAnimation(afterDelay: cellDelay)
cellDelay += delay
} else {
completionCount += 1
}
}
}
}
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-07-05 16:19:09
Jest to prosta, piękna animacja fade, którą najczęściej używałem w moim tableview
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.alpha = 0
UIView.animate(withDuration: 1) {
cell.alpha = 1.0
}
}
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-08-17 21:43:17
tableView:willDisplayCell:forRowAtIndexPath
metoda będzie wywoływana za każdym razem, gdy komórka zostanie pokazana, a ponieważ są one wyświetlane w tym samym czasie, oznacza to, że są wywoływane w różnych wątkach i nie możesz powiedzieć iOS SDK, aby wywoływał tę metodę sekwencyjnie. Więc myślę, że sposobem na uzyskanie tego, czego chcesz, jest ustawienie opóźnienia dla każdej komórki, gdy jest pokazywana.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat delay = indexPath.row * yourSupposedAnimationDuration;
[UIView animateWithDuration:yourSupposedAnimationDuration delay:delay options:UIViewAnimationOptionCurveEaseIn animations:^{
//Your animation code
}completion:^(BOOL finished) {
//Your completion Code
}];
}
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-05-02 06:50:43