Анимация при вставке большей строки в UITableView, предполагающая неправильную высоту - программирование

Анимация при вставке большей строки в UITableView, предполагающая неправильную высоту

У меня возникла проблема с анимацией добавления или удаления строки в UITableView, которая имеет разную высоту, чем другие строки.

Следующие gif демонстрируют проблему с строками высоты по умолчанию (44pts) и большей строкой (100pt), которые вставлены и удалены. Слева - экранная запись с симулятора (новая ячейка, заканчивающаяся пятой пятой, является другой проблемой), а одна справа - макет того, что он должен делать.

gif of animation issuegif of how it should look

В моем случае у меня есть ряд строк, каждый из которых занимает 60 пунктов. Когда нажата кнопка в ячейке, ячейка "редактирования" выскользнет снизу, нажав нижние ячейки вниз. Эта ячейка редактирования высотой 180pts. Когда я вызываю insertRowsAtIndexPaths:withRowAnimation: или deleteRowsAtIndexPaths:withRowAnimation:, анимация предполагает неправильную высоту 60pts, вместо 180pts она должна быть Это означает, что в случае UITableViewRowAnimationTop новая ячейка появится на -60pts с позиции, в которой она закончится, и переместится в новое положение; около трети анимации он должен делать. Между тем, строка ниже анимирует плавно от ее начального положения до 180 пунктов вниз, точно так, как должна.

Кто-нибудь разработал реальное решение? каким-то образом рассказать новую строку, какую высоту она должна быть для анимации?

Ниже приведен код, который я использую, чтобы скрыть и показать строку редактирования. Я использую TLSwipeForOptionsCell для запуска редактирования, но он легко реплицируется с использованием, например, tableView:didSelectRowAtIndexPath:

-(void)hideEditFields{
    [self.tableView beginUpdates];

    [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
    editFormVisibleForRow = -1;

    [self.tableView endUpdates];
}

-(void)cellDidSelectMore:(TLSwipeForOptionsCell *)cell{
    NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
    // do nothing if this is the currently selected row
    if(editFormVisibleForRow != indexPath.row){
        if(editFormVisibleForRow >= 0){
            [self hideEditFields];
            // update the index path, as the cell positions (may) have changed
            indexPath = [self.tableView indexPathForCell:cell];
        }

        [self.tableView beginUpdates];

        editFormVisibleForRow = indexPath.row;
        [self.tableView insertRowsAtIndexPaths:@[
                                             [NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]
                                             ] withRowAnimation:UITableViewRowAnimationTop];

        [self.tableView endUpdates];
    }
}

-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _dataSource.count + (editFormVisibleForRow >= 0 ? 1 : 0);
}

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    int row = indexPath.row;
    if(editFormVisibleForRow >= 0 && row > editFormVisibleForRow && row <= editFormVisibleForRow + 1){
        return 180.0f;
    }
    else return 60.0;
}

Похоже, что это обычная проблема без четкого ответа. Большинство подобных вопросов, которые я нашел здесь, на SO, остаются без ответа или предлагают обходные пути, характерные для ситуации с аськой. (примеры: Проблема с RowAnimation, Пользовательская высота UITableViewCell дает неправильную анимацию, Сбой анимации UITableView при удалении и вставке ячеек с разной высотой).

Кроме того, вместо того, чтобы пытаться сделать одну строку с тремя размерами, я попытался сделать три более мелкие строки и оживить их, но это не подходит, потому что все они появились сразу. Я также попытался оживить их один за другим, но облегчение сделало его странным, с очевидной 3-шаговой анимацией, вместо того, чтобы весь вид редактирования скользил из вида одним движением.

Изменить: Я только заметил, что если я вызываю reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNone для строки выше той, которую я пытаюсь оживить, она изменяет поведение анимации; а именно анимация предполагает, что высота равна 0pts, как показано в следующей анимации. Это ближе к тому, что я хочу, но все же не так, поскольку скорость анимации неверна и она оставляет пробел (в моем приложении это означает фон цвет прорывается)

gif of issue with previous row reloaded

4b9b3361

Ответ 1

Это, используя didSelectRowAtIndexPath, помог мне:

@interface TableController ()
@property (strong,nonatomic) NSArray *theData;
@property (strong,nonatomic) NSIndexPath *pathToEditCell;
@end

@implementation TableController 


- (void)viewDidLoad {
    [super viewDidLoad];
    self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine"];
    [self.tableView reloadData];
}


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return ([indexPath isEqual:self.pathToEditCell])? 100: 44;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return (self.pathToEditCell == nil)? self.theData.count: self.theData.count + 1;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if ([indexPath isEqual:self.pathToEditCell]) {
        RDEditCell *cell = [tableView dequeueReusableCellWithIdentifier:@"EditCell" forIndexPath:indexPath];
        return cell;
    }else{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        cell.textLabel.text = self.theData[indexPath.row];
        return cell;
    }
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    if (self.pathToEditCell == nil) { // first time selecting a row
        self.pathToEditCell = [NSIndexPath indexPathForRow:indexPath.row +1 inSection:indexPath.section];
        [self.tableView insertRowsAtIndexPaths:@[self.pathToEditCell] withRowAnimation:UITableViewRowAnimationAutomatic];
    }else if ([self.pathToEditCell isEqual:indexPath]){ // deletes the edit cell if you click on it
        self.pathToEditCell = nil;
        [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

    }else{ // close the old edit cell and adds another if you click on another cell while the edit cell is on screen
        [self.tableView beginUpdates];
        [self.tableView deleteRowsAtIndexPaths:@[self.pathToEditCell] withRowAnimation:UITableViewRowAnimationFade];
        self.pathToEditCell = indexPath;
        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        [self.tableView endUpdates];
    }
}

Для удаления мне нравится внешний вид опции "fade" для анимации, но "top" тоже в порядке.