Держите uitableview статичным при вставке строк вверху - PullRequest
60 голосов
/ 25 ноября 2010

У меня есть tableView, в который я вставляю строки сверху.

Пока я делаю это, я хочу, чтобы текущее представление оставалось полностью неподвижным, поэтому строки появляются только при прокрутке вверх.

Я попытался сохранить текущую позицию базового UIScrollview и сбросить позицию после вставки строк, но это приводит к дрожанию, вверх и вниз, хотя в конечном итоге он возвращается в прежнее место..

Есть ли хороший способ добиться этого?

Обновление: я использую beginUpdate, затем insertRowsAtIndexPath, endUpdates.Вызова reloadData нет.

scrollToRowAtIndexPath переходит на верх текущей ячейки (сохраняется до добавления строк).

Другой подход, который я пробовал, заканчивается в точно правильный темп, но с дрожанием.

save tableView currentOffset. (Underlying scrollView method)
Add rows (beginUpdates,insert...,endUpdates) 
reloadData ( to force a recalulation of the scrollview size )
Recalculate the correct new offset from the bottom of the scrollview
setContentOffset (Underlying scrollview method)

Проблема в том, что reloadData заставляет scrollview / tableview начать короткую прокрутку, затем setContentOffset возвращает его в правильное место.

Есть ли способ заставить tableView работать с новым размером, не запуская отображение?

Завершение всего процесса в beginAnimation commitAnimation также мало чем помогает.

Обновление 2: это можетОбязательно сделайте это - посмотрите официальное приложение для твиттера, когда вы загружаете обновления.

Ответы [ 18 ]

1 голос
/ 07 мая 2014

Только на первый взгляд кажется невозможным сделать это, если вы вернете примерную высоту для таблицы.

   - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath ;

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

Чтобы заставить его работать, используйте один из приведенных выше ответов (я пошел с ответом @Mayank Yadav), не реализуйте методtimateHeight и кэшируйте высоту ячеек (не забывая настраивать кеш при вставке дополнительных ячеек вверху) .

1 голос
/ 21 августа 2013

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

tableView.transform = CGAffineTransformMakeRotation(M_PI);

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{

   cell.transform = CGAffineTransformMakeRotation(M_PI);

}

Используйте [tableView setScrollIndicatorInsets:UIEdgeInsetsMake(0, 0, 0, 310)], чтобы установить относительное положение индикатора прокрутки. Он будет справа после поворота табличного представления.

1 голос
/ 25 ноября 2010

Как вы добавляете строки в таблицу?

Если вы меняете источник данных и затем вызываете reloadData, это может привести к повторной прокрутке таблицы вверх.

Однако, если вы используете методы beginUpdates, insertRowsAtIndexPaths:withRowAnimation:, endUpdates, вы сможете вставлять строки без необходимости вызывать reloadData, сохраняя таблицу в исходном положении.

Не забудьте изменить источник данных перед вызовом endUpdates, иначе вы получите исключение внутренней несогласованности.

0 голосов
/ 25 ноября 2010

Как насчет использования scrollToRowAtIndexPath: atScrollPosition: animated :? Вы должны иметь возможность просто добавить элемент в ваш источник данных, установить строку с помощью вышеупомянутого метода и перезагрузить таблицу ...

0 голосов
/ 17 августа 2017

ответов AmitP, версия Swift 3

let beforeContentSize = self.tableView.contentSize
self.tableView.reloadData()
let afterContentSize = self.tableView.contentSize
let afterContentOffset = self.tableView.contentOffset
let newContentOffset = CGPoint(x: afterContentOffset.x, y: afterContentOffset.y + afterContentSize.height - beforeContentSize.height)
                    self.tableView.contentOffset = newContentOffset
0 голосов
/ 27 августа 2016

Поздно к вечеринке, но это работает, даже когда ячейка имеет динамическую высоту (или UITableViewAutomaticDimension), не нужно перебирать ячейки для вычисления их размера, но работает только тогда, когда элементы добавляются в самом начале tableView и тамэто не заголовок, с небольшим количеством математики, вероятно, можно адаптировать это к любой ситуации:

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        if indexPath.row == 0 {
            self.getMoreMessages()
        }
}

private func getMoreMessages(){
        var initialOffset = self.tableView.contentOffset.y
        self.tableView.reloadData()
        //@numberOfCellsAdded: number of items added at top of the table 
        self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: numberOfCellsAdded, inSection: 0), atScrollPosition: .Top, animated: false)
        self.tableView.contentOffset.y += initialOffset
}
0 голосов
/ 05 декабря 2010

В конце концов я решил эту проблему путем рендеринга текущего табличного представления в UIImage, а затем поместив временный UIImageView поверх табличного представления, пока оно анимируется.

Следующий код создаст изображение


// Save the current tableView as an UIImage
CSize pageSize = [[self tableView] frame].size;
UIGraphicsBeginImageContextWithOptions(pageSize, YES, 0.0); // 0.0 means scale appropriate for device ( retina or no )
CGContextRef resizedContext = UIGraphicsGetCurrentContext();
CGPoint offset = [[self tableView] contentOffset];
CGContextTranslateCTM(resizedContext,-(offset.x),-(offset.y));

[[[self tableView  ]layer] renderInContext:resizedContext];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();    

Вам нужно следить за тем, насколько выросло табличное представление, вставляя строки, и убедитесь, что вы прокручиваете табличное представление обратно в ту же самую позицию.

0 голосов
/ 12 сентября 2012

Основываясь на ответе Андрея З, вот живой пример, идеально подходящий для меня ...

int numberOfRowsBeforeUpdate = [controller.tableView numberOfRowsInSection:0];
CGPoint currentOffset = controller.tableView.contentOffset;

if(numberOfRowsBeforeUpdate>0)
{
    [controller.tableView reloadData];
    int numberOfRowsAfterUpdate = [controller.tableView numberOfRowsInSection:0];

    float rowHeight = [controller getTableViewCellHeight];  //custom method in my controller
    float offset = (numberOfRowsAfterUpdate-numberOfRowsBeforeUpdate)*rowHeight;

    if(offset>0)
    {
        currentOffset.y = currentOffset.y+offset;
        [controller.tableView setContentOffset:currentOffset];
    }
}
else
    [controller.tableView reloadData];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...