UITableView меняет положение при вставке новых строк - PullRequest
0 голосов
/ 22 июня 2019

У меня есть UITableView, который реализует тип «бесконечной прокрутки».

Это делается путем вычисления IndexPath новых данных и последующей передачи на tableView.insertRows(at: indexPaths, with: .none).

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

enter image description here

Моя таблица создана с использованием этого фрагмента

  private func addTableView() {
        tableView = UITableView(frame: .zero)
        tableView.showsVerticalScrollIndicator = false
        tableView.showsHorizontalScrollIndicator = false
        tableView.rowHeight = UITableView.automaticDimension
        tableView.bounces = true
        tableView.estimatedRowHeight = 200
        tableView.separatorStyle = .none
        tableView.isHidden = true
        tableView.backgroundColor = .clear
        tableView.tableFooterView = UIView()

        addSubview(tableView)
        tableView.position(top: topAnchor, leading: leadingAnchor, bottom: bottomAnchor, trailing: trailingAnchor)

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: UITableViewCell.reuseID)
    }

И перезагрузка запускается с помощью

  func insertRows(_ indexPaths: [IndexPath]) {
        UIView.performWithoutAnimation {
            tableView.insertRows(at: indexPaths, with: .none)
            self.tableView.isHidden = false
        }
    }

Я использую performWithoutAnimation, так как мне не нравились анимации для вставки строк.

В моей модели представления я вставляю FeedTableViewProvider, соответствующий UITableViewDataSource, UITableViewDelegate, и имеет следующие методы

protocol FeedTableViewProviderType: class {
    var data: Feed? { get set }
    var feed: [FeedItem] { get }
    var insertRows: (([IndexPath]) -> Void)? { get set }
    var didRequestMoreData: ((Int) -> Void)? { get set }
}

class FeedTableViewProvider: NSObject, FeedTableViewProviderType {

    var insertRows: (([IndexPath]) -> Void)?
    var didRequestMoreData: ((Int) -> Void)?

    var data: Feed? {
        didSet {
            guard let data = data else { return }
            self.addMoreRows(data.feed)
        }
    }

    private(set) var feed = [FeedItem]() {
        didSet {
            isPaginating = false
        }
    }

    private var isPaginating = false

    private func addMoreRows(_ data: [FeedItem]) {
        var indexPaths = [IndexPath]()

        data.indices.forEach { indexPaths.append(IndexPath(row: feed.count + $0, section: 0)) }

        feed.append(contentsOf: data.sorted(by: { $0.props.createdDate > $1.props.createdDate }))

        insertRows?(indexPaths)
    }

    private func requestNextPage() {
        guard let currentPage = data?.currentPage, let totalPages = data?.totalPages, currentPage < totalPages else { return }
        didRequestMoreData?(currentPage + 1)
    }
}

extension FeedTableViewProvider: TableViewProvider {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return feed.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: UITableViewCell.reuseID, for: indexPath)
        cell.textLabel?.text = "Cell # \(indexPath.row)"
        return cell
    }

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if indexPath.item == feed.count - 1 && !isPaginating {
            isPaginating = true
            requestNextPage()
        }
    }
}

Ответы [ 3 ]

1 голос
/ 22 июня 2019

Я подозреваю, что причина этого на самом деле связана с использованием

tableView.rowHeight = UITableView.automaticDimension
....
tableView.estimatedRowHeight = 200

Положение меняется по мере изменения смещения при вставке новых ячеек.

Я бы начал с хранения какого-то кеша, содержащего высоту ваших ячеек

private var sizeCache: [IndexPath: CGFloat] = [IndexPath: CGFloat]()

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

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    sizeCache[indexPath] = cell.frame.size.height
}

Теперьубедитесь, что вы применили этот размер из кэша

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return sizeCache[indexPath] ?? UITableView.automaticDimension
}

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

0 голосов
/ 22 июня 2019

используйте этот код при добавлении новых данных в табличное представление.

  UIView.setAnimationsEnabled(false)
    self.tableView.beginUpdates()
    self.tableView.reloadSections(NSIndexSet(index: 0) as IndexSet, with: UITableViewRowAnimation.none)
    self.tableView.endUpdates()
0 голосов
/ 22 июня 2019

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

func scrollToTop(){
        DispatchQueue.main.async {
            let indexPath = IndexPath(row: self.dataArray.count-1, section: 0)
            self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...