Имейте 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)
})