Swift,将更多数据加载到表视图中会导致滚动滞后
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift,将更多数据加载到表视图中会导致滚动滞后相关的知识,希望对你有一定的参考价值。
我有一个UITableView
数据,从网址解析。
UITableView
将加载更多数据,当向右滚动时(或者有更多空间滚动,但接近结尾 - 两者都做,结果相同)
当加载更多数据时 - 我简单地将它附加到我的类的数组,其中包含TableView
的数据,然后列表滚动回超过列表的一半(例如,获得40个项目,再加载10个项目 - >滚动回到20-25)。
追加完成后调用TableView.reloadData()
。
这样做有什么错误吗?我可以共享代码,但这很常见。
class TabAllTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, XMLParserDelegate {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var BlogAllTableView: UITableView!
var loadMoreStatus = false
var maxPage = 1.0
var currentPageLoad = 1.0
var blogList: [DetailAndRenderBlogObject] = []
var eName: String = String()
var category = String()
var full_text = String()
var short_text = String()
var blog_title = String()
var avatar = String()
var full_name = String()
var url = String()
var created_at = String()
private let CATEGORY = ConfigData.CATEGORY_ALL
let cellIdentifier = "BlogTableViewCell"
override func viewDidLoad() {
super.viewDidLoad()
setupNavMenuButtons()
self.BlogAllTableView.insertSubview(refreshControl, at: 0)
self.BlogAllTableView.tableFooterView?.isHidden = true
downloadBlogData(1, true, true)
BlogAllTableView.delegate = self
BlogAllTableView.dataSource = self
}
var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action:
#selector(TabAllTableViewController.handleRefresh(_:)),
for: UIControlEvents.valueChanged)
refreshControl.tintColor = Colors.ColorLoadingIndicator
return refreshControl
}()
@objc func handleRefresh(_ refreshControl: UIRefreshControl) {
downloadBlogData(1, true, false)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
let deltaOffset = maximumOffset - currentOffset
if deltaOffset <= 0 && currentPageLoad < maxPage {
loadMore()
}
}
func loadMore() {
if ( !loadMoreStatus ) {
self.loadMoreStatus = true
self.activityIndicator.startAnimating()
self.BlogAllTableView.tableFooterView?.isHidden = false
downloadBlogData(currentPageLoad, false, false)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.sideMenuController?.isLeftViewEnabled = true
AppDelegate.tabBarReference.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.navigationBar.topItem?.title = "all".localized()
}
private func setupNavMenuButtons() {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(handleMenuRefresh))
let image = UIImage(named:"menu_ham.png")
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView.image = image
let imageHeight = navigationController?.navigationBar.frame.size.height
let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: imageHeight!, height: imageHeight!))
wrapperView.addSubview(imageView)
imageView.center = CGPoint(x: imageView.frame.size.width / 2, y: wrapperView.frame.size.height / 2)
let tap = UITapGestureRecognizer(target: self, action: #selector(TabAllTableViewController.menuButtonClick))
wrapperView.addGestureRecognizer(tap)
let btnHamburgerMenu: UIBarButtonItem = UIBarButtonItem(customView: wrapperView)
navigationItem.setLeftBarButton(btnHamburgerMenu, animated: false)
}
@objc private func menuButtonClick()
{
self.sideMenuController?.showLeftViewAnimated()
}
@objc private func handleMenuRefresh() {
downloadBlogData(1, true, true)
}
func numberOfSections(in tableView: UITableView) -> Int {
return blogList.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if (section != 0) {
return 12
} else {
return CGFloat.leastNonzeroMagnitude
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.0)
return view
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(ConfigData.CELL_HEIGHT)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? BlogTableViewCell else {
fatalError("The dequeued cell is not an instance of BlogTableViewCell.")
}
cell.layer.cornerRadius = 10
let blogItem = blogList[indexPath.section]
cell.avatarBackground.contentMode = .scaleAspectFill
cell.avatarBackground.layer.cornerRadius = cell.avatarBackground.frame.size.width / 2;
cell.avatarBackground.clipsToBounds = true;
if let authorImgUrl = URL(string: blogItem.authorImg) {
cell.authorRoundImage.contentMode = .scaleAspectFill
cell.authorRoundImage.layer.cornerRadius = cell.authorRoundImage.frame.size.width / 2;
cell.authorRoundImage.clipsToBounds = true;
//Helper.downloadImage(url: authorImgUrl, imageview: cell.authorRoundImage)
cell.authorRoundImage.sd_setImage(with: authorImgUrl)
}
if let headerImageUrl = URL(string: blogItem.image) {
cell.bigImage.contentMode = .scaleToFill
//Helper.downloadImage(url: headerImageUrl, imageview: cell.bigImage)
cell.bigImage.sd_setImage(with: headerImageUrl)
}
cell.authorLabel.text = blogItem.author
cell.dateLabel.text = blogItem.date
cell.title.text = blogItem.title
cell.titleDescription.text = blogItem.shortDescription
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let secondViewController = self.storyboard!.instantiateViewController(withIdentifier: "ShowArticleViewController") as! ShowArticleViewController
secondViewController.blogItem = blogList[indexPath.section]
self.navigationController!.pushViewController(secondViewController, animated: true)
}
private func downloadBlogData(_ page : Double, _ refresh : Bool, _ showOverlay : Bool) {
// print(InAppProperties.sharedInstance.getDefaulLang())
if showOverlay {
LoadingOverlay.shared.showOverlay(view: self.view)
}
let req = NSMutableURLRequest(url: NSURL(string: Helper.getBlogUrl(CATEGORY, Int(page)))! as URL)
req.httpMethod = "GET"
req.httpBody = "key="value"".data(using: String.Encoding.utf8) //This isn't for GET requests, but for POST requests so you would
URLSession.shared.dataTask(with: req as URLRequest) { data, response, error in
if error != nil {
//Your HTTP request failed.
print(error?.localizedDescription)
} else {
//Your HTTP request succeeded
if refresh {
self.currentPageLoad = 1
} else {
self.currentPageLoad += 1
}
let stringData = String(data: data!, encoding: String.Encoding.utf8)!
//print(stringData)
let xml = SWXMLHash.parse(stringData)
if page == 1 {
self.blogList = [DetailAndRenderBlogObject]()
}
for elem in xml["response"]["provider"].all {
let itemList = elem["item"]
for article in itemList.all {
let blogItem = DetailAndRenderBlogObject()
blogItem.articleUrl = article["url"].element!.text
blogItem.author = article["full_name"].element!.text
blogItem.authorImg = article["avatar"].element!.text
blogItem.text = article["full_text"].element!.text
blogItem.shortDescription = article["short_text"].element!.text
blogItem.title = article["title"].element!.text
blogItem.categoryUrl = article["category"].element!.text
blogItem.image = self.repairLink(article["thumbnail"].element!.text)
blogItem.date = self.formatDate(article["created_at"].element!.text)
if (blogItem.categoryUrl.lowercased().range(of:"video") == nil &&
blogItem.title.lowercased().range(of: "видео") == nil) {
self.blogList.append(blogItem)
}
}
if let totalItemsCount = xml["response"]["pagination"]["totalCount"].element?.text {
self.maxPage = (Double(totalItemsCount)! / 10).rounded(.up)
}
}
DispatchQueue.main.async {
self.BlogAllTableView.reloadData()
self.refreshControl.endRefreshing()
self.loadMoreStatus = false
self.activityIndicator.stopAnimating()
self.BlogAllTableView.tableFooterView?.isHidden = true
if showOverlay {
LoadingOverlay.shared.hideOverlayView()
}
if (page == 1) {
let indexPath = NSIndexPath(row: 0, section: 0)
self.BlogAllTableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
}
}
}
}.resume()
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
eName = elementName
if elementName == "item" {
category = String()
full_text = String()
short_text = String()
blog_title = String()
avatar = String()
full_name = String()
url = String()
created_at = String()
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
let blogListItem = DetailAndRenderBlogObject()
blogListItem.categoryUrl = category
blogListItem.text = full_text
blogListItem.shortDescription = short_text
blogListItem.title = blog_title
blogListItem.authorImg = avatar
blogListItem.author = full_name
blogListItem.articleUrl = url
blogListItem.date = created_at
print("WRITING DATA")
blogList.append(blogListItem)
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
//print("ENAME: " + eName)
switch eName {
case "category":
print("writing category: " + string)
category = string;
case "full_text":
full_text = string;
case "short_text":
short_text = string;
case "title":
title = string;
case "thumbnail":
avatar = string;
case "avatar":
avatar = string;
case "full_name":
full_name = string;
case "url":
url = string;
case "created_at":
created_at = string;
default:
()
}
}
func parserDidEndDocument(_ parser: XMLParser) {
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func repairLink(_ link : String) -> String { //sometimes links looks like https://asdasd.comhttps://asdasd.com/...
let newLink = link.suffix(from: link.index(link.startIndex, offsetBy: 1))
if let range = newLink.range(of: "http") {
let substring = newLink[range.lowerBound...]
return String(substring)
}
return link
}
func formatDate(_ date : String) -> String { //date String "2018-01-22 08:59:43"
if let dividerIndex = date.index(of: " ") {
return String(date[..<dividerIndex])
}
return date
}
}
答案
重新加载整个表是一个非常密集的操作。更好的方法可能是使用tableView.insertRows(at:with:)
方法。一个例子是 - 像 -
func didFinishLoadingData(newBlogs: [DetailAndRenderBlogObject]) {
tableView.beginUpdates()
var indexPaths: [IndexPath] = []
for row in (blogList.count..<(blogList.count + newBlogs.count)) {
indexPaths.append(IndexPath(row: row, section: 0))
}
blogList.append(contentsOf: newBlogs)
tableView.insertRows(at: indexPaths, with: .fade)
tableView.endUpdates()
}
以上是关于Swift,将更多数据加载到表视图中会导致滚动滞后的主要内容,如果未能解决你的问题,请参考以下文章