reloadData () из UITableView с динамическими высотами ячеек вызывает нервную прокрутку
Я чувствую, что это может быть общей проблемой, и мне было интересно, есть ли какое-либо общее решение для этого.
в принципе, мой UITableView имеет динамические высоты ячеек для каждой ячейки. Если я не нахожусь в верхней части UITableView и я tableView.reloadData()
, прокрутка становится нервным.
Я считаю, что это связано с тем, что, поскольку я перезагрузил данные, когда я прокручиваю вверх, UITableView пересчитывает высоту для каждой ячейки, входящей в видимость. Как мне смягчить это, или как я только reloadData от определенного IndexPath до конца UITableView?
кроме того, когда мне удается прокрутить весь путь до вершины, я могу прокручивать вниз, а затем вверх, без проблем без прыжков. Это, скорее всего, потому, что высоты UITableViewCell уже были рассчитаны.
9 ответов:
чтобы предотвратить прыжки, вы должны сохранить высоту ячеек при их загрузке и дать точное значение в
tableView:estimatedHeightForRowAtIndexPath
:// declare cellHeightsDictionary NSMutableDictionary *cellHeightsDictionary; // initialize in code (thanks to @Gerharbo) cellHeightsDictionary = @{}.mutableCopy; // declare table dynamic row height and create correct constraints in cells tableView.rowHeight = UITableViewAutomaticDimension; // save height - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { [cellHeightsDictionary setObject:@(cell.frame.size.height) forKey:indexPath]; } // give exact height value - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { NSNumber *height = [cellHeightsDictionary objectForKey:indexPath]; if (height) return height.doubleValue; return UITableViewAutomaticDimension; }
Swift 3 версия принятого ответа.
var cellHeights: [IndexPath : CGFloat] = [:] func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { cellHeights[indexPath] = cell.frame.size.height } func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return cellHeights[indexPath] ?? 70.0 }
прыжок из-за плохой расчетной высоте. Чем больше расчетная высота отличается от фактической высоты, тем больше таблица может прыгать при перезагрузке, особенно чем дальше она прокручивается. Это связано с тем, что расчетный размер таблицы радикально отличается от ее фактического размера, что заставляет таблицу корректировать размер и смещение содержимого. Таким образом, расчетная высота не должна быть случайным значением, но близко к тому, что вы думаете, что высота будет. Я также испытал, когда я набор
UITableViewAutomaticDimension
если ваши клетки одного типа, тоfunc viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 100//close to your cell height }
Если у вас есть верность ячеек в разных разделах, то я думаю, что лучшее место
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { //Return different sizes for different cells if you need to return 100 }
@Igor ответ работает нормально в этом случае,
Swift-4
код.// declaration & initialization var cellHeightsDictionary: [IndexPath: CGFloat] = [:]
в следующих методах
UITableViewDelegate
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // print("Cell height: \(cell.frame.size.height)") self.cellHeightsDictionary[indexPath] = cell.frame.size.height } func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { if let height = self.cellHeightsDictionary[indexPath] { return height } return UITableViewAutomaticDimension }
я столкнулся с этим сегодня и заметил:
- это только iOS 8, действительно.
- переменная
cellForRowAtIndexPath
не помогает.исправление было на самом деле довольно просто:
переопределить
estimatedHeightForRowAtIndexPath
и убедитесь, что она возвращает правильные значения.С этим все странное дрожание и прыжки в моих UITableViews прекратились.
примечание: Я на самом деле знаю размер моих клеток. Есть только два возможных значения. Если ваш ячейки действительно имеют переменный размер, тогда вы можете кэшировать
cell.bounds.size.height
СtableView:willDisplayCell:forRowAtIndexPath:
вы можете на самом деле перезагрузить только определенные строки с помощью
reloadRowsAtIndexPaths
, например:tableView.reloadRowsAtIndexPaths(indexPathArray, withRowAnimation: UITableViewRowAnimation.None)
но, в общем, вы также можете анимировать изменения высоты ячейки таблицы следующим образом:
tableView.beginUpdates() tableView.endUpdates()
Я пробовал все обходные пути выше, но ничего не сработало.
проведя часы и пройдя через все возможные разочарования, выяснил способ исправить это. Это решение-Спаситель жизни! Сработало как по волшебству!
Swift 4
let lastContentOffset = tableView.contentOffset tableView.beginUpdates() tableView.endUpdates() tableView.layer.removeAllAnimations() tableView.setContentOffset(lastContentOffset, animated: false)
я добавил его в качестве расширения, чтобы код выглядел чистым и не писал все эти строки каждый раз, когда я хотел перезагрузить.
extension UITableView { func reloadWithoutAnimation() { let lastScrollOffset = contentOffset beginUpdates() endUpdates() layer.removeAllAnimations() setContentOffset(lastScrollOffset, animated: false) } }
наконец-то ..
tableView.reloadWithoutAnimation()