Можете ли вы анимировать изменение высоты на UITableViewCell при выборе?

Я использую UITableView в своем приложении для iPhone, и у меня есть список людей, принадлежащих к группе. Мне бы хотелось, чтобы, когда пользователь нажимает на конкретного человека (выбирая таким образом ячейку), высота ячейки увеличивается, чтобы отобразить несколько элементов управления пользовательского интерфейса для редактирования свойств этого человека.

Возможно ли это?

вопрос задан 20.01.2009
David White
2049 репутация

19 ответов


  • 844 рейтинг

    Я нашел ДЕЙСТВИТЕЛЬНО ПРОСТОЕ решение этой проблемы как побочный эффект для UITableView, над которым я работал. , , , ,

    Сохраните высоту ячейки в переменной, которая обычно сообщает исходную высоту через tableView: heightForRowAtIndexPath:, затем, когда вы хотите анимировать изменение высоты, просто измените значение переменной и вызовите ее. , ,

    [tableView beginUpdates];
    [tableView endUpdates];
    

    Вы обнаружите, что он не выполняет полную перезагрузку, но достаточно для UITableView, чтобы знать, что он должен перерисовать ячейки, получая новое значение высоты для ячейки. , , , и угадай что? Это оживляет изменения для вас. Милая.

    У меня есть более подробное объяснение и полные примеры кода в моем блоге. , , Animate UITableView Изменение высоты ячейки

    ответ дан Simon Lee, с репутацией 21400, 14.01.2010
  • 56 рейтинг

    Мне нравится ответ Саймона Ли. На самом деле я не пробовал этот метод, но, похоже, он изменит размер всех ячеек в списке. Я надеялся на изменение только той ячейки, которая прослушивается. Я сделал это как Саймон, но с небольшой разницей. Это изменит внешний вид ячейки при ее выборе. И это оживляет. Просто еще один способ сделать это.

    Создайте int для хранения значения для текущего индекса выбранной ячейки:

    int currentSelection;
    

    Тогда:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        int row = [indexPath row];
        selectedNumber = row;
        [tableView beginUpdates];
        [tableView endUpdates];
    }
    

    Тогда:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        if ([indexPath row] == currentSelection) {
            return  80;
        }
        else return 40;
    
    
    }
    

    Я уверен, что вы можете внести аналогичные изменения в tableView: cellForRowAtIndexPath: изменить тип ячейки или даже загрузить файл XIB для ячейки.

    Таким образом, currentSelection начнется с 0. Вам нужно будет внести коррективы, если вы не хотите, чтобы первая ячейка списка (с индексом 0) выглядела выделенной по умолчанию.

    ответ дан Mark A., с репутацией 820, 25.04.2011
  • 19 рейтинг

    Добавить свойство для отслеживания выбранной ячейки

    @property (nonatomic) int currentSelection;
    

    Установите для него значение часового в (например) viewDidLoad, чтобы убедиться, что UITableView запускается в «нормальном» положении

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        //sentinel
        self.currentSelection = -1;
    }
    

    В heightForRowAtIndexPath вы можете установить желаемую высоту для выбранной ячейки

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        int rowHeight;
        if ([indexPath row] == self.currentSelection) {
            rowHeight = self.newCellHeight;
        } else rowHeight = 57.0f;
        return rowHeight;
    }
    

    В didSelectRowAtIndexPath вы сохраняете текущий выбор и сохраняете динамическую высоту, если требуется

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
            // do things with your cell here
    
            // set selection
            self.currentSelection = indexPath.row;
            // save height for full text label
            self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10;
    
            // animate
            [tableView beginUpdates];
            [tableView endUpdates];
        }
    }
    

    В didDeselectRowAtIndexPath установите индекс выбора обратно в значение часового и анимируйте ячейку обратно в нормальную форму

    - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {       
            // do things with your cell here
    
            // sentinel
            self.currentSelection = -1;
    
            // animate
            [tableView beginUpdates];
            [tableView endUpdates];
        }
    }
    
    ответ дан Joy, с репутацией 191, 5.08.2013
  • 13 рейтинг

    reloadData не годится, потому что нет анимации. , ,

    Вот что я сейчас пытаюсь:

    NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
    

    Это почти работает правильно. Почти. Я увеличиваю высоту ячейки, и иногда в представлении таблицы происходит небольшой «сбой» при замене ячейки, как будто сохраняется некоторая позиция прокрутки в представлении таблицы, новая ячейка (которая является первой ячейкой). в таблице) заканчивается слишком большим смещением, и представление прокрутки отскакивает, чтобы изменить его положение.

    ответ дан lawrence, с репутацией 5375, 6.05.2009
  • 10 рейтинг

    Я решил с reloadRowsAtIndexPaths.

    Я сохраняю в didSelectRowAtIndexPath indexPath выбранной ячейки и вызываю reloadRowsAtIndexPaths в конце (вы можете отправить NSMutableArray для списка элементов, которые вы хотите перезагрузить).

    В heightForRowAtIndexPath вы можете проверить, есть ли indexPath в списке или нет ячеек expandIndexPath и высота отправки.

    Вы можете проверить этот базовый пример: https: // github. com / ferminhg / iOS-примеры / дерево / master / iOS-UITableView-Cell-Height-Change / celdascambiadetam Это простое решение.

    я добавлю код, если вам помочь

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return 20;
    }
    
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath
    {
        if ([indexPath isEqual:_expandIndexPath])
            return 80;
    
        return 40;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"Celda";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
        [cell.textLabel setText:@"wopwop"];
    
        return cell;
    }
    
    #pragma mark -
    #pragma mark Tableview Delegate Methods
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        NSMutableArray *modifiedRows = [NSMutableArray array];
        // Deselect cell
        [tableView deselectRowAtIndexPath:indexPath animated:TRUE];
        _expandIndexPath = indexPath;
        [modifiedRows addObject:indexPath];
    
        // This will animate updating the row sizes
        [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
    }
    
    ответ дан fermin, с репутацией 508, 14.11.2014
  • 10 рейтинг

    Я не знаю, что все эти вещи о последовательном вызове beginUpdates / endUpdates, вы можете просто использовать -[UITableView reloadRowsAtIndexPaths:withAnimation:]. Вот пример проекта .

    ответ дан axiixc, с репутацией 1678, 2.08.2014
  • 3 рейтинг
    BOOL flag;
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        flag = !flag;
        [tableView beginUpdates];
        [tableView reloadRowsAtIndexPaths:@[indexPath] 
                         withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView endUpdates];
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES == flag ? 20 : 40;
    }
    
    ответ дан Roman Solodyashkin, с репутацией 455, 15.08.2016
  • 2 рейтинг

    Попробуйте это для расширения индексной строки:

    @property (nonatomic) NSIndexPath *expandIndexPath;
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
    {
    if ([indexPath isEqual:self.expandedIndexPath])
        return 100;
    
    return 44;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
    NSMutableArray *modifiedRows = [NSMutableArray array];
    if ([indexPath isEqual:self.expandIndexPath]) {
        [modifiedRows addObject:self.expandIndexPath];
        self.expandIndexPath = nil;
    } else {
        if (self.expandedIndexPath)
            [modifiedRows addObject:self.expandIndexPath];
    
        self.expandIndexPath = indexPath;
        [modifiedRows addObject:indexPath];
    }
    
    // This will animate updating the row sizes
    [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
    
    // Preserve the deselection animation (if desired)
    [tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier];
        cell.textLabel.text = [NSString stringWithFormat:@"I'm cell %ld:%ld", (long)indexPath.section, (long)indexPath.row];
    
    return cell;
    }
    
    ответ дан Nagarjun, с репутацией 3880, 24.09.2014
  • 2 рейтинг

    просто заметка для кого-то вроде меня, ищущего добавить "Подробнее" в пользовательской ячейке.

    [tableView beginUpdates];
    [tableView endUpdates];
    

    Проделал отличную работу, но не забудьте "обрезать" вид ячейки. В Интерфейсном Разработчике выберите Вашу Ячейку - & gt; Просмотр содержимого - & gt; из инспектора свойств выберите « клип subview »

    ответ дан Anthony Marchenko, с репутацией 300, 25.03.2015
  • 1 рейтинг

    Вот более короткая версия Simons для Swift 3. Также позволяет переключать выбор ячейки

    var cellIsSelected: IndexPath?
    
    
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        cellIsSelected = cellIsSelected == indexPath ? nil : indexPath
        tableView.beginUpdates()
        tableView.endUpdates()
      }
    
    
      func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if cellIsSelected == indexPath {
          return 250
        }
        return 65
      }
    
    ответ дан aBikis, с репутацией 158, 30.05.2017
  • 1 рейтинг

    Свифт Версия ответа Саймона Ли.

    // MARK: - Variables 
      var isCcBccSelected = false // To toggle Bcc.
    
    
    
        // MARK: UITableViewDelegate
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    
        // Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath()
        if self.cellTypes[indexPath.row] == CellType.Bcc {
            if (isCcBccSelected) {
                return 44
            } else {
                return 0
            }
        }
    
        return 44.0
    }
    

    Тогда в didSelectRowAtIndexPath ()

      func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
    
        // To Get the Focus of CC, so that we can expand Bcc
        if self.cellTypes[indexPath.row] == CellType.Cc {
    
            if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell {
    
                if cell.tag == 1 {
                    cell.recipientTypeLabel.text = "Cc:"
                    cell.recipientTextField.userInteractionEnabled = true
                    cell.recipientTextField.becomeFirstResponder()
    
                    isCcBccSelected = true
    
                    tableView.beginUpdates()
                    tableView.endUpdates()
                }
            }
        }
    }
    
    ответ дан ioopl, с репутацией 1274, 7.06.2016
  • 0 рейтинг

    Входы -

    tableView. beginUpdates () Tableview. endUpdates () эти функции не будут вызывать

    func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - & gt; UITableViewCell {}

    Но если вы это сделаете, tableView. reloadRows (at: [selectedIndexPath! как IndexPath], с:. нет)

    Это назовет func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - & gt; UITableViewCell {} эта функция.

    ответ дан sRoy, с репутацией 157, 28.03.2018
  • 0 рейтинг

    Я использовал потрясающий ответ @ Joy, и он отлично работал с ios 8. 4 и XCode 7. 1. 1.

    Если вы хотите, чтобы ваша ячейка переключалась, я изменил -tableViewDidSelect следующим образом:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    //This is the bit I changed, so that if tapped once on the cell, 
    //cell is expanded. If tapped again on the same cell, 
    //cell is collapsed. 
        if (self.currentSelection==indexPath.row) {
            self.currentSelection = -1;
        }else{
            self.currentSelection = indexPath.row;
        }
            // animate
            [tableView beginUpdates];
            [tableView endUpdates];
    
    }
    

    Я надеюсь, что все это помогло вам.

    ответ дан Septronic, с репутацией 764, 19.11.2015
  • 0 рейтинг

    Проверьте этот метод после iOS 7 и более поздних версий.

    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return UITableViewAutomaticDimension;
    }
    

    В iOS 8 были сделаны улучшения. Мы можем установить его как свойство самого табличного представления.

    ответ дан iGo, с репутацией 1800, 4.03.2016
  • 0 рейтинг

    Swift версия ответ Саймона Ли :

    tableView.beginUpdates()
    tableView.endUpdates()
    

    Имейте в виду, что вы должны изменить свойства высоты ДО endUpdates().

    ответ дан Tamás Sengel, с репутацией 23088, 8.02.2018
  • 0 рейтинг

    Вот мой код пользовательского подкласса UITableView, который расширяет UITextView в ячейке таблицы без перезагрузки (и потерял фокус клавиатуры):

    - (void)textViewDidChange:(UITextView *)textView {
        CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height;
        // Check, if text height changed
        if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) {
            [self beginUpdates];
    
            // Calculate difference in height
            CGFloat difference = textHeight - self.previousTextHeight;
    
            // Update currently editing cell's height
            CGRect editingCellFrame = self.editingCell.frame;
            editingCellFrame.size.height += difference;
            self.editingCell.frame = editingCellFrame;
    
            // Update UITableView contentSize
            self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference);
    
            // Scroll to bottom if cell is at the end of the table
            if (self.editingNoteInEndOfTable) {
                self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference);
            } else {
                // Update all next to editing cells
                NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell];
                for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) {
                    UITableViewCell *cell = self.visibleCells[i];
                    CGRect cellFrame = cell.frame;
                    cellFrame.origin.y += difference;
                    cell.frame = cellFrame;
                }
            }
            [self endUpdates];
        }
        self.previousTextHeight = textHeight;
    }
    
    ответ дан Vitaliy Gozhenko, с репутацией 6084, 10.11.2015
  • 0 рейтинг

    Да, это возможно.

    UITableView имеет метод делегата didSelectRowAtIndexPath

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [UIView animateWithDuration:.6
                              delay:0
             usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState
              initialSpringVelocity:0
                            options:UIViewAnimationOptionBeginFromCurrentState animations:^{
    
                                cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
                                NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
                                [violatedTableView beginUpdates];
                                [violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];
                                [violatedTableView endUpdates];
                            }
                         completion:^(BOOL finished) {
        }];
    }
    

    Но в вашем случае, если пользователь прокручивает и выбирает другую ячейку, вам нужно иметь последнюю выбранную ячейку, чтобы уменьшить и расширить текущую выбранную ячейку. reloadRowsAtIndexPaths: вызывает heightForRowAtIndexPath:, поэтому обрабатывайте соответственно.

    ответ дан Koushik, с репутацией 610, 1.08.2016
  • -1 рейтинг

    Я только что решил эту проблему с небольшим взломом:

    static int s_CellHeight = 30;
    static int s_CellHeightEditing = 60;
    
    - (void)onTimer {
        cellHeight++;
        [tableView reloadData];
        if (cellHeight < s_CellHeightEditing)
            heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain];
    }
    
    - (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
            if (isInEdit) {
                return cellHeight;
            }
            cellHeight = s_CellHeight;
            return s_CellHeight;
    }
    

    Когда мне нужно увеличить высоту ячейки, я устанавливаю isInEdit = YES и вызываю метод [self onTimer], и он оживляет рост ячейки, пока не достигнет значения s_CellHeightEditing :-)

    ответ дан Dzamir, с репутацией 144, 20.08.2009
  • -2 рейтинг

    Получите путь индекса выбранной строки. Перезагрузите стол. В методе heightForRowAtIndexPath объекта UITableViewDelegate установите высоту выбранной строки на другую высоту, а для остальных верните обычную высоту строки

    ответ дан lostInTransit, с репутацией 38092, 21.01.2009