Имейте reloadData для анимации UITableView при изменении
У меня есть UITableView, который имеет два режима. Когда мы переключаемся между режимами, у меня разное количество секций и ячеек в каждом разделе. В идеальном случае, когда таблица будет расти или сжиматься, она будет делать крутую анимацию.
Вот код, который я пробовал, но он ничего не делает:
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.5];
[self.tableView reloadData];
[UIView commitAnimations];
Любые мысли о том, как я могу это сделать?
Ответы
Ответ 1
Собственно, это очень просто:
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
Из документация:
Вызов этого метода приводит к тому, что представление таблицы запрашивает его источник данных для новые ячейки для указанных разделов. В представлении таблицы вставка новых ячеек, поскольку он оживляет старые ячейки.
Ответ 2
Возможно, вы захотите использовать:
Objective-C
[UIView transitionWithView: self.tableView
duration: 0.35f
options: UIViewAnimationOptionTransitionCrossDissolve
animations: ^(void)
{
[self.tableView reloadData];
}
completion: nil];
Swift
UIView.transitionWithView(tableView,
duration: 0.35,
options: .TransitionCrossDissolve,
animations:
{ () -> Void in
self.tableView.reloadData()
},
completion: nil);
Swift 3
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
Никаких проблем.: D
Вы также можете использовать любой из UIViewAnimationOptionTransitions
для более холодных эффектов:
-
TransitionNone
-
TransitionFlipFromLeft
-
TransitionFlipFromRight
-
TransitionCurlUp
-
TransitionCurlDown
-
TransitionCrossDissolve
-
TransitionFlipFromTop
-
TransitionFlipFromBottom
Ответ 3
Получите больше свободы, используя класс CATransition
.
Оно не ограничивается исчезновением, но может также выполнять движения.
Например:
(не забудьте импортировать 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"];
Измените type
в соответствии с вашими потребностями, например, kCATransitionFade
и т.д.
Реализация в Swift:
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
Swift 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()
Ответ 4
Я считаю, что вы можете просто обновить свою структуру данных, а затем:
[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];
Кроме того, "withRowAnimation" не является булевым, но имеет стиль анимации:
UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle
Ответ 5
Все эти ответы предполагают, что вы используете UITableView только с 1 секцией.
Чтобы точно обрабатывать ситуации, в которых вы используете более одного раздела:
NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
(Примечание: вы должны убедиться, что у вас больше 0 секций!)
Еще одна вещь, которую нужно отметить, - это запустить NSInternalInconsistencyException, если вы попытаетесь одновременно обновить источник данных с помощью этого кода. Если это так, вы можете использовать логику, подобную этой:
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];
Ответ 6
Способ подхода к этому заключается в том, чтобы сообщить tableView удалить и добавить строки и разделы с помощью
insertRowsAtIndexPaths:withRowAnimation:
deleteRowsAtIndexPaths:withRowAnimation:
insertSections:withRowAnimation:
и
deleteSections:withRowAnimation:
методов UITableView. Когда вы вызываете эти методы, таблица будет анимировать в/из запрошенных вами элементов, а затем вызвать reloadData сама по себе, чтобы вы могли обновить состояние после этой анимации. Эта часть важна - если вы окунаете все, но не меняете данные, возвращаемые таблицей dataSource, строки появятся снова после завершения анимации.
Итак, ваш поток приложений будет выглядеть следующим образом:
[self setTableIsInSecondState:YES];
[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];
Пока ваши методы dataSource таблицы возвращают правильный новый набор разделов и строк, проверяя [self tableIsInSecondState]
(или что-то еще), это приведет к тому, что вы ищете.
Ответ 7
Я не могу комментировать верхний ответ, но быстрая реализация:
self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)
вы можете включить столько разделов, сколько хотите обновить в первом аргументе для reloadSections.
Другие анимации, доступные из документов:
https://developer.apple.com/reference/uikit/uitableviewrowanimation
увядает
Вставляемая или удаленная строка или строки исчезают в виде таблицы или из нее.
вправо
Вставленные строки или строки сдвигаются справа; удаленные строки или строки сдвигаются вправо.
влево
Вставленные строки или строки перемещаются слева; удаленные строки или строки сдвигаются влево.
верхний
Вставленные строки или строки перемещаются сверху; удаленные строки или строки выходят вверх.
снизу
Вставленные строки или ряды скользят снизу; удаленные строки или строки сдвигаются вниз.
case none
Вставленные или удаленные строки используют анимацию по умолчанию.
средний
В представлении таблицы делается попытка сохранить старые и новые ячейки с центром в пространстве, которое они сделали или будут занимать. Доступно в iPhone 3.2.
автоматический
Вид таблицы выбирает для вас подходящий стиль анимации. (Представлено в iOS 5.0.)
Ответ 8
Версия Swift 4 для ответа @dmarnel:
tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
Ответ 9
Быстрая реализация:
let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
Ответ 10
Для Swift 4
tableView.reloadSections([0], with: UITableView.RowAnimation.fade)
Ответ 11
В моем случае я хотел добавить еще 10 строк в tableview (для функции "показать больше результатов" ), и я сделал следующее:
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];
В большинстве случаев вместо "self.numberOfRows" вы обычно используете счетчик массива объектов для tableview. Поэтому, чтобы убедиться, что это решение работает хорошо для вас, "arrayOfIndexPaths" должен быть точным массивом путей указателей вставляемых строк. Если строка существует для любого из этих указательных путей, код может упасть, поэтому вы должны использовать метод "reloadRowsAtIndexPaths: withRowAnimation:" для этих указательных путей, чтобы избежать сбоев
Ответ 12
Если вы хотите добавить свои собственные анимации в ячейки UITableView, используйте
[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];
чтобы получить массив видимых ячеек. Затем добавьте произвольную анимацию в каждую ячейку.
Отметьте эту суть, которую я опубликовал для гладкой пользовательской анимации ячеек.
https://gist.github.com/floprr/1b7a58e4a18449d962bd
Ответ 13
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];
Ответ 14
Анимация без reloadData() в Swift может быть выполнена следующим образом (начиная с версии 2.2):
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()
если вам нужно вызвать reloadData() после окончания анимации, вы можете принять изменения в CATransaction следующим образом:
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()
Логика показана для случая, когда вы удаляете строки, но эта же идея работает и для добавления строк. Вы также можете изменить анимацию на UITableViewRowAnimation.Left, чтобы сделать ее опрятной или выбрать из списка других доступных анимаций.
Ответ 15
To перезагрузить все разделы, а не только один с пользовательской продолжительностью.
Пользовательский параметр duration
в 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)
})