Обновить раздел без заголовка раздела перезагрузки

У меня есть 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. Если у вас есть только один обработчик (источник данных и делегат), легко изменить приведенный выше код для достижения тех же результатов.