#ios #swift #uitableview #scroll #pagination
#iOS #swift #uitableview #прокрутка #разбивка на страницы
Вопрос:
Мое приложение использует UITableView для реализации пользовательского интерфейса в стиле TikTok. Каждая ячейка равна высоте всего экрана. Разбивка на страницы включена, и это отлично работает для первой партии из 10 загружаемых записей. Каждая UITableViewCell — это одна «страница». Пользователь может «перелистывать» страницы, проводя пальцем, и изначально каждая «страница» полностью переворачивается, как и ожидалось. Однако, когда я добавляю дополнительные строки, проверяя, является ли видимая в данный момент ячейка последней, а затем загружаю еще 10 строк, разбивка на страницы выходит из строя. В результате прокрутки получается частично «перевернутая» ячейка — части двух ячеек видны одновременно. Я пробовал разные вещи, но я даже не уверен, в чем проблема. Кажется, что TableView теряет геометрию.
Примечание: после сбоя разбивки на страницы я могу полностью вернуться к первой ячейке. В этот момент UITableView, похоже, восстанавливает самообладание, и я снова могу корректно просматривать все загруженные строки, включая новые.
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// Pause the video if the cell is ended displaying
if let cell = cell as? HomeTableViewCell {
cell.pause()
}
if let indices = tableView.indexPathsForVisibleRows {
for index in indices {
if index.row >= self.data.count - 1 {
self.viewModel!.getPosts()
break
}
}
}
}
Комментарии:
1. Можно попробовать метод TableView.scrollToItem, чтобы исправить положение ячейки.
2. Я столкнулся с той же проблемой, поэтому я отказался от UITableView и использовал gist.github.com/chanonly123/fd58b04b73e930fd0feef97d3aa732fe
3. @ChanOnly123 — спасибо, я попробовал несколько разных способов использования scrollToItem, но пока не нашел ни одного подхода, который решал бы проблему. Большое спасибо за этот альтернативный код — если это окажется фундаментальным ограничением UITableView, я попробую ваш код следующим. Приветствия!
4. @ChanOnly123 — Я задал вопрос в вашем github — не могли бы вы взглянуть, если у вас есть минутка? Спасибо!!
Ответ №1:
Чтобы создать UX в стиле «Tik Tok», я закончил тем, что использовал структуру текстур вместе с поставщиком облачного видео (mux.com ). Теперь работает нормально.
Ответ №2:
Я столкнулся с той же проблемой, и поскольку я не мог найти решение где-либо еще, вот как я решил ее без использования текстуры:
Я использовал UITableViewDataSourcePrefetching
протокол для извлечения новых данных для вставки
extension TikTokTableView: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
viewModel.prefetchRows(at: indexPaths)
}
}
prefetchRows
выполнит запрос, если видимая ячейка является последней, как в моем случае
func prefetchRows(at indexPaths: [IndexPath]) {
if indexPaths.contains(where: isLastCell) {
getPosts(type: typeOfPosts, offset: posts.count, lastPostId: lastPost)
}
}
private func isLastCell(for indexPath: IndexPath) -> Bool {
return indexPath.row == posts.count - 1
}
У меня есть weak var view
тип делегата TikTokTableViewDelegate
в моей модели представления, чтобы иметь доступ к функции insertItems
, реализованной my TikTokTableView
. Эта функция используется для информирования UITableView
о том, куда вставлять входящие сообщения
self.posts.append(contentsOf: response.posts)
let indexPathsToReload = self.calculateIndexPathToReload(from: response.posts)
self.view?.insertItems(at: indexPathsToReload)
private func calculateIndexPathToReload(from newPosts: [Post]) -> [IndexPath] {
let startIndex = posts.count - newPosts.count
let endIndex = startIndex newPosts.count
print(startIndex, endIndex)
return (startIndex..<endIndex).map { IndexPath(row: $0, section: 0) }
}
и это insertItems
функция, реализованная в TikTokTableView
, и вот ключ: если мы попытаемся вставить эти строки, разбивка на страницы таблицы завершится ошибкой и оставит это странное смещение, мы должны сохранить indexPaths в локальном свойстве и вставить их после завершения анимации прокрутки.
extension TikTokTableView: TikTokTableViewDelegate {
func insertItems(at indexPathsToReload: [IndexPath]) {
DispatchQueue.main.async {
// if we try to insert rows in the table, the scroll animation will be stopped and the cell will have a weird offset
// that's why we keep the indexPaths and insert them on scrollViewDidEndDecelerating(:)
self.indexPathsToReload = indexPathsToReload
}
}
}
Поскольку UITableView
это подкласс UIScrollView
, к которому у нас есть доступ scrollViewDidEndDecelerating
, эта функция запускается в конце прокрутки пользователя, и это время, когда мы вставляем новые строки
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if !indexPathsToReload.isEmpty {
tableView.insertRows(at: indexPathsToReload, with: .none)
indexPathsToReload = []
}
}