Обновить раздел без заголовка раздела перезагрузки
У меня есть UITableView
, где в заголовке есть UISegmentedControl
. Он должен работать точно так же, как в приложении App Store: по мере прокрутки пользователя заголовок в заголовке прокручивается с экрана, а segmentedControl
- под navigationBar
.
![screen]()
Когда пользователь выбирает сегмент, раздел под заголовком должен быть перезагружен с помощью nice UITableViewRowAnimation
. Однако, как я называю tableView:reloadSections:withRowAnimation:
, заголовок также анимируется, что я хочу предотвратить, потому что он выглядит ужасно.
Вот мой код для этого:
- (void)selectedSegmentIndexChanged:(UISegmentedControl *)sender
{
int index = sender.selectedSegmentIndex;
if (index < self.oldIndex) {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationLeft];
} else if (index > self.oldIndex) {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationRight];
}
self.oldIndex = index;
}
У кого-нибудь есть идея, как перезагрузить раздел под заголовком без перезагрузки самого заголовка?
Ответы
Ответ 1
Возможно, вам стоит попробовать
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationLeft] //or UITableViewRowAnimationRight
Однако я не уверен, но я думаю, что может возникнуть некоторая ошибка в случае, когда у вас меньше строк для перезагрузки, чем раньше.
Изменить
Я думаю, что вы можете иметь дело с [tableView beginUpdates]
и [tableView endUpdates]
, чтобы решить вашу проблему.
Например, у вас есть 2 массива данных для отображения. Назовите их oldArray
и newArray
.
Пример того, как вы могли бы сделать:
- (void)selectedSegmentIndexChanged:(UISegmentedControl *)sender
{
[self.tableView setDataSource: newArray];
int nbRowToDelete = [oldArray count];
int nbRowToInsert = [newArray count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < nbRowToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < nbRowToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
Ответ 2
Если вы используете Swift 2.0, не стесняйтесь использовать это расширение.
Будьте предупреждены: передача неправильных oldCount
или newCount
приведет к сбою программы.
extension UITableView{
func reloadRowsInSection(section: Int, oldCount:Int, newCount: Int){
let maxCount = max(oldCount, newCount)
let minCount = min(oldCount, newCount)
var changed = [NSIndexPath]()
for i in minCount..<maxCount {
let indexPath = NSIndexPath(forRow: i, inSection: section)
changed.append(indexPath)
}
var reload = [NSIndexPath]()
for i in 0..<minCount{
let indexPath = NSIndexPath(forRow: i, inSection: section)
reload.append(indexPath)
}
beginUpdates()
if(newCount > oldCount){
insertRowsAtIndexPaths(changed, withRowAnimation: .Fade)
}else if(oldCount > newCount){
deleteRowsAtIndexPaths(changed, withRowAnimation: .Fade)
}
if(newCount > oldCount || newCount == oldCount){
reloadRowsAtIndexPaths(reload, withRowAnimation: .None)
}
endUpdates()
}
Ответ 3
Попробуйте следующее:
BOOL needsReloadHeader = YES;
UIView *oldHeaderView = nil;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerToReturn = nil;
if(needsReloadHeader == YES) {
headerToReturn = [[UIView alloc] init];
// ...
// custom your header view in this block
// and save
// ...
oldHeaderView = headerToReturn;
} else {
headerToReturn = oldHeaderView;
}
return headerToReturn;
}
Просто нужно изменить "needsReloadHeader" на "NO" в других местах.
Ответ 4
Простой ответ просто не перезагружает разделы анимированные, просто используйте UITableViewRowAnimationNone.
В настоящий момент вы используете UITableViewRowAnimationLeft и UITableViewRowAnimationRight, которые также перемещают ваш раздел и выходят.
Однако даже с UITableViewRowAnimationNone строки все равно будут анимированы, если количество ячеек перед обновлением будет отличаться от числа после обновления.
Кроме того, прочитайте эту тему, здесь.
Приветствия.
Ответ 5
An objective-c версия расширения Intentss
@interface UITableView (Extensions)
- (void)reloadRowsInSection:(NSUInteger)sectionIndex withRowAnimation:(UITableViewRowAnimation)rowAnimation oldCount:(NSUInteger)oldCount newCount:(NSUInteger)newCount;
@end
@implementation UITableView (Extensions)
- (void)reloadRowsInSection:(NSUInteger)sectionIndex withRowAnimation:(UITableViewRowAnimation)rowAnimation oldCount:(NSUInteger)oldCount newCount:(NSUInteger)newCount {
NSUInteger minCount = MIN(oldCount, newCount);
NSMutableArray *insert = [NSMutableArray array];
NSMutableArray *delete = [NSMutableArray array];
NSMutableArray *reload = [NSMutableArray array];
for (NSUInteger row = oldCount; row < newCount; row++) {
[insert addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
for (NSUInteger row = newCount; row < oldCount; row++) {
[delete addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
for (NSUInteger row = 0; row < minCount; row++) {
[reload addObject:[NSIndexPath indexPathForRow:row inSection:sectionIndex]];
}
[self beginUpdates];
[self insertRowsAtIndexPaths:insert withRowAnimation:rowAnimation];
[self deleteRowsAtIndexPaths:delete withRowAnimation:rowAnimation];
[self reloadRowsAtIndexPaths:reload withRowAnimation:rowAnimation];
[self endUpdates];
}
@end
Ответ 6
Вы перезагружаете раздел, поэтому ясно, что все в разделе будет перезагружено (включая заголовок).
Почему бы вместо этого не поместить UISegmentedControl внутри UITableView tableHeaderView
? Это позволит точно выполнить ваше поведение.
Ответ 7
Вот еще один способ, который вы могли бы использовать и по-прежнему использовать анимации.
Скажем, у вас есть динамический DataSource, который изменяется, когда вы что-то выбираете, и вы хотите обновлять только строки этого раздела, оставляя заголовок раздела сверху, нетронутым.
/** I get the desired handler from the handler collection. This handler is just a
simple NSObject subclass subscribed to UITableViewDelegate and UITableViewDataSource
protocols. **/
id handler = [self.tableViewHandlers objectForKey:[NSNumber numberWithInteger:index]];
/** Get the rows which will be deleted */
NSInteger numberOfRows = [self.tableView numberOfRowsInSection:sectionIndex];
NSMutableArray* indexPathArray = [NSMutableArray array];
for (int rowIndex = 0; rowIndex < numberOfRows; rowIndex++){
[indexPathArray addObject:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]];
}
/** Update the handler */
[self.tableView setDataSource:handler];
[self.tableView setDelegate:handler];
/** Get the rows which will be added */
NSInteger newNumberOfRows = [handler tableView:self.tableView numberOfRowsInSection:sectionIndex];
NSMutableArray* newIndexPathArray = [NSMutableArray array];
for (int rowIndex = 0; rowIndex < newNumberOfRows; rowIndex++){
[newIndexPathArray addObject:[NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex]];
}
/** Perform updates */
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:newIndexPathArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
В качестве примечания, пожалуйста, придерживайтесь указанного порядка операций, это требует UITableView.
Если у вас есть только один обработчик (источник данных и делегат), легко изменить приведенный выше код для достижения тех же результатов.