修复 iOS 下拉刷新动画
Fix iOS pull to refresh animation
这是我的刷新控件代码。
(代码已更新为完整的 ViewController 代码以便更好地理解)
import UIKit
class AirportTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AirportRequestDelegate {
@IBOutlet weak var airportTable: UITableView!
var airportRequest = AirportRequest()
var airportList = [AirportDetail]()
var refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Airport List"
airportTable.delegate = self
airportRequest.delegate = self
airportRequest.fetchAirports()
airportTable.dataSource = self
refreshControl.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged)
airportTable.addSubview(refreshControl)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return airportList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = airportTable.dequeueReusableCell(withIdentifier: "airportTableCell", for: indexPath)
myCell.textLabel?.text = self.airportList[indexPath.row].AirportName
myCell.detailTextLabel?.text = self.airportList[indexPath.row].StationName
myCell.accessoryType = .disclosureIndicator
return myCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.airportTable.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.airportList.remove(at: indexPath.row)
airportTable.deleteRows(at: [indexPath], with: .top)
}
}
// The AirportRequestDelegate adds this function and is called once airport list is fetched
func didUpdateAirports(_ airportRequest: AirportRequest, airports: [AirportDetail]) {
// copies the airport list to a local variable so that it can be used with the tableView delegate functions
self.airportList = airports
// updating the UI
DispatchQueue.main.async {
self.airportTable.reloadData()
self.refreshControl.endRefreshing()
}
}
@objc func refresh(sender: UIRefreshControl) {
airportRequest.fetchAirports()
}
}
在下图中,您可以看到动画没有按预期运行。我该如何解决。最好我希望动画继续,直到 tableView 更新。
您在调用 fetchAirports()
后立即结束动画,我认为这是一个异步网络请求或延迟完成的东西。
如果您想等到获取机场并更新 table,请向该函数添加一个完成闭包。类似的东西:
func fetchAirports(@escaping completion: (() -> Void) {
// Perform the network request and once it finishes, call completion()
networkRequest() {
completion()
}
}
然后在你的刷新方法中:
@objc func refresh(sender: UIRefreshControl) {
airportRequest.fetchAirports(completion: { [weak self] in
self?.sender.endRefreshing()
})
}
试试吧..
@objc func refresh(sender: UIRefreshControl) {
refreshControl.beginRefreshing()
airportRequest.fetchAirports(completion: { [weak self] in
self?.tableView?.reloadData()
refreshControl?.endRefreshing()
})
}
在table中插入新数据后可以调用该方法。
refreshControl.endRefreshing()
将刷新控件添加为子视图可能会出现问题。 UITableView 现在有 属性 用于刷新控件。在这里,您可以从 apple 文档中了解您应该如何实现:
https://developer.apple.com/documentation/uikit/uirefreshcontrol
在 didUpdateAirports 中放置一个断点并查看从何处(以及何时)调用它。动画只应在调用 endRefreshing 后停止。
也许数据没有变化,所以你可能得到一个缓存的响应,这将导致非常快速的 endRefreshing 调用。
您也可以输入一个简单的打印 ("ending animation now") 语句来实时查看它。
这是我的刷新控件代码。 (代码已更新为完整的 ViewController 代码以便更好地理解)
import UIKit
class AirportTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AirportRequestDelegate {
@IBOutlet weak var airportTable: UITableView!
var airportRequest = AirportRequest()
var airportList = [AirportDetail]()
var refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Airport List"
airportTable.delegate = self
airportRequest.delegate = self
airportRequest.fetchAirports()
airportTable.dataSource = self
refreshControl.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged)
airportTable.addSubview(refreshControl)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return airportList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = airportTable.dequeueReusableCell(withIdentifier: "airportTableCell", for: indexPath)
myCell.textLabel?.text = self.airportList[indexPath.row].AirportName
myCell.detailTextLabel?.text = self.airportList[indexPath.row].StationName
myCell.accessoryType = .disclosureIndicator
return myCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.airportTable.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.airportList.remove(at: indexPath.row)
airportTable.deleteRows(at: [indexPath], with: .top)
}
}
// The AirportRequestDelegate adds this function and is called once airport list is fetched
func didUpdateAirports(_ airportRequest: AirportRequest, airports: [AirportDetail]) {
// copies the airport list to a local variable so that it can be used with the tableView delegate functions
self.airportList = airports
// updating the UI
DispatchQueue.main.async {
self.airportTable.reloadData()
self.refreshControl.endRefreshing()
}
}
@objc func refresh(sender: UIRefreshControl) {
airportRequest.fetchAirports()
}
}
在下图中,您可以看到动画没有按预期运行。我该如何解决。最好我希望动画继续,直到 tableView 更新。
您在调用 fetchAirports()
后立即结束动画,我认为这是一个异步网络请求或延迟完成的东西。
如果您想等到获取机场并更新 table,请向该函数添加一个完成闭包。类似的东西:
func fetchAirports(@escaping completion: (() -> Void) {
// Perform the network request and once it finishes, call completion()
networkRequest() {
completion()
}
}
然后在你的刷新方法中:
@objc func refresh(sender: UIRefreshControl) {
airportRequest.fetchAirports(completion: { [weak self] in
self?.sender.endRefreshing()
})
}
试试吧..
@objc func refresh(sender: UIRefreshControl) {
refreshControl.beginRefreshing()
airportRequest.fetchAirports(completion: { [weak self] in
self?.tableView?.reloadData()
refreshControl?.endRefreshing()
})
}
在table中插入新数据后可以调用该方法。
refreshControl.endRefreshing()
将刷新控件添加为子视图可能会出现问题。 UITableView 现在有 属性 用于刷新控件。在这里,您可以从 apple 文档中了解您应该如何实现: https://developer.apple.com/documentation/uikit/uirefreshcontrol
在 didUpdateAirports 中放置一个断点并查看从何处(以及何时)调用它。动画只应在调用 endRefreshing 后停止。
也许数据没有变化,所以你可能得到一个缓存的响应,这将导致非常快速的 endRefreshing 调用。
您也可以输入一个简单的打印 ("ending animation now") 语句来实时查看它。