UITableView 滚动到不需要的索引或位置

UITableView Scrolls To Undesired Index or Position

基本上,任务是在用户在 UITableView 中向下滚动时加载新的 API 响应,而不停止用户交互并保持当前位置(Facebook 和 Instagram 等实时订阅)。

我想要做的是使用自定义单元格解析并查看 Rest API 在 UITableView 中的响应。

问题是,当用户滚动到底部时,会进行 API 调用,并且 table 视图会滚动到用户所在的其他位置。

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return array.count;
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "xxxxx", for:indexPath) as! xxxxxxxx

    return cell;
}



func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if scrollView == tableView {
        if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height) {
            print("Scroll Ended")
            fetchDataFromApi()
        }
    }
}


func fetchDataFromApi() {

    let jsonUrlString = "xxxxxxx"


    guard let url = URL(string: jsonUrlString) else {
        return
    }

    print(url)

    URLSession.shared.dataTask(with: url) {(data,response,err) in

        guard let data = data else {
            return
        }
        do {
            let apiResponseData = try JSONDecoder().decode(ApiResponse.self, from: data)

            if apiResponseData.httpStatusCode == HttpStatusCode.OK {

                if let apiResponse = apiResponseData.data{
                    self.array.append(contentsOf: apiResponse)
                }


                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }

            }
            else {
                print("API Response Error : \(apiResponseData.httpStatusCode) \(apiResponseData.errorMessage)")
            }
        }catch let jsonErr {
            print("Serialization Error \(jsonErr)")
        }
        }.resume()
}}

试试这个

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "xxxxx", for:indexPath) as! xxxxxxxx

    let lastRowIndex = tableView.numberOfRows(inSection: tableView.numberOfSections-1)

    if (indexPath.row == lastRowIndex - 1) {
         //print("last row selected")
        fetchDataFromApi()
    }

    return cell;
}

如果你正在使用这个就不需要调用这个方法

scrollViewDidEndDragging

尝试insertCellAtIndexPath替换

中的tableview.reloadData()
if let apiResponse = apiResponseData.data{
                self.array.append(contentsOf: apiResponse)
            }


            DispatchQueue.main.async {
                self.tableView.reloadData()
            }

......

有几种方法可以实现这一点。据我所知,最有利的是实现分页 API 并在 UITableView 的最后一项后调用 API 。您可以使用:

public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let botEdge = scrollView.contentOffset.y + scrollView.frame.size.height;

if (botEdge >= scrollView.contentSize.height)
{
// Call API and reload TableView on completion handler.
}
}

在 API 方法的完成处理程序上调用 tableView 重新加载。

或者你可以用稍微笨拙的方式来做:

public var indexPathsForVisibleRows: [NSIndexPath]? { get }

获取当前可见单元格的索引路径数组,并在重新加载 UITableView 后滚动到索引:

tableView.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.None, animated: false)

这是因为我在 table 视图中设置了动态单元格大小