我正在使用swift构建RSS阅读器,需要实现pull to reload功能。
以下是我尝试这样做的方法。
class FirstViewController: UIViewController,
UITableViewDelegate, UITableViewDataSource {
@IBOutlet var refresh: UIScreenEdgePanGestureRecognizer
@IBOutlet var newsCollect: UITableView
var activityIndicator:UIActivityIndicatorView? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.newsCollect.scrollEnabled = true
// Do any additional setup after loading the view, typically from a nib.
if nCollect.news.count <= 2{
self.collectNews()
}
else{
self.removeActivityIndicator()
}
view.addGestureRecognizer(refresh)
}
@IBAction func reload(sender: UIScreenEdgePanGestureRecognizer) {
nCollect.news = News[]()
return newsCollect.reloadData()
}
我得到了:
财产&#39; self.refresh&#39;没有在super.init调用
初始化
请帮助我了解手势识别器的行为。一个可用的示例代码将是一个很好的帮助。
感谢。
答案 0 :(得分:506)
拉动刷新是在iOS中构建的。你可以像在
那样迅速地做到这一点var refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(refresh(_:)), for: UIControl.Event.valueChanged)
tableView.addSubview(refreshControl) // not required when using UITableViewController
}
@objc func refresh(sender:AnyObject) {
// Code to refresh table view
}
在某些时候你可能会结束更新。
refreshControl.endRefreshing()
答案 1 :(得分:124)
故事板和快速解决方案......
1。)打开.storyboard文件,在故事板中选择一个TableViewController,然后选择&#34;启用&#34;表视图控制器 - 实用程序中的刷新功能。
2.打开关联的UITableViewController-Class并将以下行添加到viewDidLoad-Method中。
self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
Swift 2.2中的OR :
self.refreshControl?.addTarget(self, action: #selector(TestTableViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
3.)在viewDidLoad-Method
上面添加以下方法func refresh(sender:AnyObject)
{
// Updating your data here...
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
答案 2 :(得分:63)
我想提一下自iOS 10以来一直包含的 PRETTY COOL 功能,其中包括:
目前,UICollectionView
,UITableView
和UIScrollView
的每一个都直接支持UIRefreshControl!
这些视图中的每一个都有refreshControl实例属性,这意味着不再需要在滚动视图中将其添加为子视图,您所要做的就是:
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(doSomething), for: .valueChanged)
// this is the replacement of implementing: "collectionView.addSubview(refreshControl)"
collectionView.refreshControl = refreshControl
}
func doSomething(refreshControl: UIRefreshControl) {
print("Hello World!")
// somewhere in your code you might need to call:
refreshControl.endRefreshing()
}
就我个人而言,我发现将其视为滚动视图的属性比将其添加为子视图更自然,特别是因为作为UIRefreshControl的超级视图的唯一合适视图是滚动视图,即使用的功能UIRefreshControl仅在使用滚动视图时有用;这就是为什么这种方法应该更明显地设置刷新控制视图。
但是,您仍然可以选择使用基于iOS版本的addSubview
:
if #available(iOS 10.0, *) {
collectionView.refreshControl = refreshControl
} else {
collectionView.addSubview(refreshControl)
}
答案 3 :(得分:37)
Swift 4
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)
tableView.addSubview(refreshControl)
}
@objc func refresh(_ sender: Any) {
// your code to refresh tableView
}
你可以停止刷新:
refreshControl.endRefreshing()
答案 4 :(得分:7)
快捷键5
private var pullControl = UIRefreshControl()
pullControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
pullControl.addTarget(self, action: #selector(refreshListData(_:)), for: .valueChanged)
if #available(iOS 10.0, *) {
tableView.refreshControl = pullControl
} else {
tableView.addSubview(pullControl)
}
// Actions
@objc private func refreshListData(_ sender: Any) {
self.pullControl.endRefreshing() // You can stop after API Call
// Call API
}
答案 5 :(得分:6)
在 Swift 中使用此功能
如果您想在WebView中进行刷新,
所以试试这段代码:
override func viewDidLoad() {
super.viewDidLoad()
addPullToRefreshToWebView()
}
func addPullToRefreshToWebView(){
var refreshController:UIRefreshControl = UIRefreshControl()
refreshController.bounds = CGRectMake(0, 50, refreshController.bounds.size.width, refreshController.bounds.size.height) // Change position of refresh view
refreshController.addTarget(self, action: Selector("refreshWebView:"), forControlEvents: UIControlEvents.ValueChanged)
refreshController.attributedTitle = NSAttributedString(string: "Pull down to refresh...")
YourWebView.scrollView.addSubview(refreshController)
}
func refreshWebView(refresh:UIRefreshControl){
YourWebView.reload()
refresh.endRefreshing()
}
答案 6 :(得分:5)
然而,经过进一步的实验,我发现建议的解决方案有时会导致不那么漂亮UI glitch。
相反,选择this approach *为我做了诀窍。
//Create an instance of a UITableViewController. This will host your UITableView.
private let tableViewController = UITableViewController()
//Add tableViewController as a childViewController and set its tableView property to your UITableView.
self.addChildViewController(self.tableViewController)
self.tableViewController.tableView = self.tableView
self.refreshControl.addTarget(self, action: "refreshData:", forControlEvents: .ValueChanged)
self.tableViewController.refreshControl = self.refreshControl
答案 7 :(得分:2)
我构建了一个RSS Feed应用程序,其中我有一个 Pull To refresh 功能,该功能最初具有上面列出的一些问题。
但是为了向用户添加上面的答案,我无处不在寻找我的用例并找不到它。我正在从网上下载数据(RSSFeed),我想要下载我的tableView故事刷新。
上面提到的内容涵盖了正确的领域,但是遇到了人们遇到的一些问题,这就是我所做的,并且它起作用:
我采用@Blankarsch的方法并进入我的main.storyboard并选择表格视图以使用刷新,然后没有提到的是创建IBOutlet和IBAction以有效地使用刷新
//Created from main.storyboard cntrl+drag refresh from left scene to assistant editor
@IBOutlet weak var refreshButton: UIRefreshControl
override func viewDidLoad() {
......
......
//Include your code
......
......
//Is the function called below, make sure to put this in your viewDidLoad
//method or not data will be visible when running the app
getFeedData()
}
//Function the gets my data/parse my data from the web (if you havnt already put this in a similar function)
//remembering it returns nothing, hence return type is "-> Void"
func getFeedData() -> Void{
.....
.....
}
//From main.storyboard cntrl+drag to assistant editor and this time create an action instead of outlet and
//make sure arguments are set to none and note sender
@IBAction func refresh() {
//getting our data by calling the function which gets our data/parse our data
getFeedData()
//note: refreshControl doesnt need to be declared it is already initailized. Got to love xcode
refreshControl?.endRefreshing()
}
&#13;
希望这有助于任何与我相同情况的人
答案 8 :(得分:2)
错误告诉您的是refresh
未初始化。请注意,您选择使refresh
不是可选的,在Swift中,它意味着 在您调用super.init
之前有(或者它被隐式调用,这似乎是你的情况)。要么refresh
可选(可能是你想要的),要么以某种方式初始化它。
我建议再次阅读Swift介绍性文档,其中详细介绍了这一点。
最后一件事,不是答案的一部分,正如@Anil所指出的那样,在iOS中有一个内置的拉动刷新控件叫UIRefresControl
,这可能是值得研究的东西。
答案 9 :(得分:2)
func pullToRefresh(){
let refresh = UIRefreshControl()
refresh.addTarget(self, action: #selector(handleTopRefresh(_:)), for: .valueChanged )
refresh.tintColor = UIColor.appBlack
self.tblAddressBook.addSubview(refresh)
}
@objc func handleTopRefresh(_ sender:UIRefreshControl){
self.callAddressBookListApi(isLoaderRequired: false)
sender.endRefreshing()
}
答案 10 :(得分:1)
我建议在每个班级中使用“拉到刷新”的扩展名。
1)制作一个空的swift文件:File - New - File - Swift File。
2)添加以下
// AppExtensions.swift
import Foundation
import UIKit
var tableRefreshControl:UIRefreshControl = UIRefreshControl()
//MARK:- VIEWCONTROLLER EXTENSION METHODS
public extension UIViewController
{
func makePullToRefreshToTableView(tableName: UITableView,triggerToMethodName: String){
tableRefreshControl.attributedTitle = NSAttributedString(string: "TEST: Pull to refresh")
tableRefreshControl.backgroundColor = UIColor.whiteColor()
tableRefreshControl.addTarget(self, action: Selector(triggerToMethodName), forControlEvents: UIControlEvents.ValueChanged)
tableName.addSubview(tableRefreshControl)
}
func makePullToRefreshEndRefreshing (tableName: String)
{
tableRefreshControl.endRefreshing()
//additional codes
}
}
3)在View Controller中,将这些方法称为:
override func viewWillAppear(animated: Bool) {
self.makePullToRefreshToTableView(bidderListTable, triggerToMethodName: "pullToRefreshBidderTable")
}
4)在某些时候你想结束刷新:
func pullToRefreshBidderTable() {
self.makePullToRefreshEndRefreshing("bidderListTable")
//Code What to do here.
}
OR
self.makePullToRefreshEndRefreshing("bidderListTable")
答案 11 :(得分:1)
我要使用
进行刷新DGElasticPullToRefresh
https://github.com/gontovnik/DGElasticPullToRefresh
<强>安装强>
pod&#39; DGElasticPullToRefresh&#39;
import DGElasticPullToRefresh
并将此函数放入swift文件中并从
中调用此函数
覆盖func viewWillAppear(_ animated:Bool)
func Refresher() {
let loadingView = DGElasticPullToRefreshLoadingViewCircle()
loadingView.tintColor = UIColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0)
self.table.dg_addPullToRefreshWithActionHandler({ [weak self] () -> Void in
//Completion block you can perfrom your code here.
print("Stack Overflow")
self?.table.dg_stopLoading()
}, loadingView: loadingView)
self.table.dg_setPullToRefreshFillColor(UIColor(red: 255.0/255.0, green: 57.0/255.0, blue: 66.0/255.0, alpha: 1))
self.table.dg_setPullToRefreshBackgroundColor(self.table.backgroundColor!)
}
并且不要忘记删除引用,而视图将获得消失
删除pull以刷新将此代码放入
覆盖func viewDidDisappear(_ animated:Bool)
override func viewDidDisappear(_ animated: Bool) {
table.dg_removePullToRefresh()
}
它看起来像
快乐编码:)
答案 12 :(得分:0)
由于可定制性较低、代码重复以及下拉刷新控制带来的错误,我创建了一个库 PullToRefreshDSL,它使用 DSL
模式,就像 SnapKit
// You only have to add the callback, rest is taken care of
tableView.ptr.headerCallback = { [weak self] in // weakify self to avoid strong reference
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { // your network call
self?.tableView.ptr.isLoadingHeader = false // setting false will hide the view
}
}
你只需要在任何 UIScrollView 子类后添加魔法关键字 ptr
,即 UITableView/UICollectionView
你不必下载库,你可以探索和修改源代码,我只是指出一个可能的 iOS 下拉刷新实现
答案 13 :(得分:0)
您可以通过使用几行代码来实现。那为什么要陷在第三方库或UI中呢? 拉动刷新是iOS内置的。您可以像这样
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({ region: 'ap-south-1', apiVersion: '2012-08-10' });
exports.handler = function(event, context, callback) {
var userSessionToken = event.headers.sessionToken;
var userEmailId = event.queryStringParameters.emailId;
var tmp = event.methodArn.split(':');
var apiGatewayArnTmp = tmp[5].split('/');
var resource = '/';
if (apiGatewayArnTmp[3]) {
resource += apiGatewayArnTmp[3];
}
var authResponse = {};
if (userSessionToken && userEmailId) {
callback(null, validateUserSession(userSessionToken, userEmailId));
} else {
callback("session token or email id is missing");
}
const generatePolicy = (principalId, effect, resource) => {
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17'; // default version
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke'; // default action
statementOne.Effect = effect;
statementOne.Resource = resource;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
return authResponse;
}
const generateAllow = (principalId, resource) => {
return generatePolicy(principalId, 'Allow', resource);
};
const generateDeny = (principalId, resource) => {
return generatePolicy(principalId, "Deny", resource);
}
const validateUserSession = (userSessionToken, userEmailId) => {
var params = {
Key: {
"username": {
S: userEmailId
},
"sessionToken": {
S: userSessionToken
}
},
TableName: "mytable"
};
dynamodb.getItem(params, function(err, data) {
if(err) {
callback(null, generateDeny('user', event.methodArn));
} else {
let currentUnixTime = new Date().getTime();
let sessionTime = data.Item.session_created_at.N;
let isSessionExpired = (currentUnixTime - 900) < sessionTime;
if(isSessionExpired){
callback(null, generateDeny('user', event.methodArn));
} else {
callback(null, generateAllow('user', event.methodArn));
}
}
});
}
};
答案 14 :(得分:0)
import UIKit
public extension UIScrollView {
private var refreshControlIsAnimatingTag: Int { return 999 }
func addRefreshControll(actionTarget: Any?, action: Selector, replaceIfExist: Bool = false) {
if !replaceIfExist && refreshControl != nil { return }
let _refreshControl = UIRefreshControl()
_refreshControl.addTarget(self, action: #selector(refreshControllValueChanged), for: .valueChanged)
_refreshControl.addTarget(actionTarget, action: action, for: .valueChanged)
refreshControl = _refreshControl
}
func showRefreshControllActivityIndicatorView(changeContentOffsetWithAnimation: Bool = true, completion: (() -> Void)? = nil) {
guard let refreshControl = refreshControl,
!refreshControl.isRefreshing else { return }
refreshControl.tag = refreshControlIsAnimatingTag
let contentOffset = CGPoint(x: 0, y: -refreshControl.frame.height )
setContentOffset(contentOffset, animated: changeContentOffsetWithAnimation)
refreshControl.beginRefreshing()
completion?()
}
func pullAndRefresh() {
guard let refreshControl = refreshControl,
!refreshControl.isRefreshing,
refreshControl.tag != refreshControlIsAnimatingTag else { return}
showRefreshControllActivityIndicatorView { refreshControl.sendActions(for: .valueChanged) }
}
func endRefreshing(deadline: DispatchTime? = nil) {
guard refreshControl?.tag ?? -1 == refreshControlIsAnimatingTag else { return }
refreshControl?.tag = 0
guard let deadline = deadline else { refreshControl?.endRefreshing(); return }
DispatchQueue.global(qos: .default).asyncAfter(deadline: deadline) { [weak self] in
DispatchQueue.main.async { self?.refreshControl?.endRefreshing() }
}
}
@objc func refreshControllValueChanged() { refreshControl?.tag = refreshControlIsAnimatingTag }
}
// Add refresh control to UICollectionView / UITableView / UIScrollView
private func setupTableView() {
let tableView = UITableView()
// ...
tableView.addRefreshControll(actionTarget: self, action: #selector(refreshData))
}
@objc func refreshData(_ refreshControl: UIRefreshControl) {
tableView?.endRefreshing(deadline: .now() + .seconds(3))
}
// Stop refreshing in UICollectionView / UITableView / UIScrollView
tableView.endRefreshing()
// Simulate pull to refresh in UICollectionView / UITableView / UIScrollView
tableView.pullAndRefresh()
别忘了在此处添加解决方案代码
import UIKit
class ViewController: UIViewController {
private weak var tableView: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
private func setupTableView() {
let tableView = UITableView()
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.dataSource = self
tableView.addRefreshControll(actionTarget: self, action: #selector(refreshData))
self.tableView = tableView
}
}
extension ViewController {
@objc func refreshData(_ refreshControl: UIRefreshControl) {
tableView?.endRefreshing(deadline: .now() + .seconds(3))
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int { return 1 }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "\(indexPath)"
return cell
}
}
答案 15 :(得分:0)
这就是我使用Xcode 7.2的方法,我认为这是一个主要的错误。我在UITableViewController
viewWillAppear
内使用它
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: "configureMessages", forControlEvents: .ValueChanged)
refreshControl!.beginRefreshing()
configureMessages()
func configureMessages() {
// configuring messages logic here
self.refreshControl!.endRefreshing()
}
正如您所看到的,我确实必须在设置configureMessage()
之后调用UIRefreshControl
方法,之后,后续刷新将正常工作。
答案 16 :(得分:0)
you can use this subclass of tableView:
import UIKit
protocol PullToRefreshTableViewDelegate : class {
func tableViewDidStartRefreshing(tableView: PullToRefreshTableView)
}
class PullToRefreshTableView: UITableView {
@IBOutlet weak var pullToRefreshDelegate: AnyObject?
private var refreshControl: UIRefreshControl!
private var isFirstLoad = true
override func willMoveToSuperview(newSuperview: UIView?) {
super.willMoveToSuperview(newSuperview)
if (isFirstLoad) {
addRefreshControl()
isFirstLoad = false
}
}
private func addRefreshControl() {
refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: "refresh", forControlEvents: .ValueChanged)
self.addSubview(refreshControl)
}
@objc private func refresh() {
(pullToRefreshDelegate as? PullToRefreshTableViewDelegate)?.tableViewDidStartRefreshing(self)
}
func endRefreshing() {
refreshControl.endRefreshing()
}
}
1 - in interface builder change the class of your tableView to PullToRefreshTableView
or create a PullToRefreshTableView
programmatically
2 - implement the PullToRefreshTableViewDelegate
in your view controller
3 - tableViewDidStartRefreshing(tableView: PullToRefreshTableView)
will be called in your view controller when the table view starts refreshing
4 - call yourTableView.endRefreshing()
to finish the refreshing
答案 17 :(得分:-1)
其他答案是正确但更多细节请查看此帖子Pull to Refresh
在Storyboard中启用刷新
当您使用UITableViewController时,解决方案非常简单:首先,在故事板中选择表视图控制器,打开属性检查器,然后启用刷新:
UITableViewController配备了一个开箱即用的UIRefreshControl引用。您只需连接一些内容即可在用户下拉时启动并完成刷新。
覆盖viewDidLoad()
在覆盖viewDidLoad()时,添加目标以处理刷新,如下所示:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.refreshControl?.addTarget(self, action: "handleRefresh:", forControlEvents: UIControlEvents.ValueChanged)
}
refreshControl.endRefreshing()
欲了解更多信息,请参阅链接,并将所有信用转到该帖子