如何在Swift中使用pull刷新?

xra*_*age 214 xcode ios uirefreshcontrol swift

我正在使用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()
}
Run Code Online (Sandbox Code Playgroud)

我正进入(状态 :

属性'self.refresh'未在super.init调用中初始化

请帮助我理解手势识别器的行为.一个工作示例代码将是一个很好的帮助.

谢谢.

Ani*_*ese 538

Pull to refresh是在iOS中构建的.你可以像swift那样做

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  
}
Run Code Online (Sandbox Code Playgroud)

在某些时候,你可以结束刷新.

refreshControl.endRefreshing()
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!我用过这个.只是一些调整,懒惰加载.我会这样做:"lazy var refreshControl = UIRefreshControl()"我发现避免强制解包变量是一种很好的做法,因为它感觉它会破坏语言的安全性. (12认同)
  • 只需快速说明,您甚至不需要将refreshControl添加到tableview.这是隐含处理的. (9认同)
  • 我怎样才能将此解决方案用于桌面视图的顶部和底部? (3认同)
  • Swift 4更新:refreshControl.addTarget(自身,操作:“ refresh:”,用于:.valueChanged) (3认同)
  • 魔法!它也适用于UICollectionView::) (2认同)

Bla*_*ank 135

故事板和快速解决方案......

1.)打开.storyboard文件,在故事板中选择TableViewController,并在"实用程序"中"启用"表视图控制器 - 刷新功能.

在此输入图像描述

2.)打开关联的UITableViewController-Class并将以下行添加到viewDidLoad-Method中.

self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
Run Code Online (Sandbox Code Playgroud)

或者在Swift 2.2中:

self.refreshControl?.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged)
Run Code Online (Sandbox Code Playgroud)

3.)在viewDidLoad-Method上方添加以下方法

self.refreshControl?.addTarget(self, action: #selector(TestTableViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
Run Code Online (Sandbox Code Playgroud)

  • 此外,您可以通过控制 - 从故事板中的"刷新控件"拖动到ViewController来添加故事板的刷新操作 (7认同)

Ahm*_*d F 70

iOS 10 - Swift 3(也适用于iOS 11 - Swift 4)

我想提一下自iOS 10以来一直包含的PRETTY COOL功能,它是:

目前,UIRefreshControl直接支持每个UICollectionView,UITableViewUIScrollView!

这些视图中的每一个都有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()
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,我觉得将它作为滚动视图的属性处理比将其添加为子视图更自然,特别是因为作为UIRefreshControl的超级视图的唯一合适的视图是滚动视图,即使用UIRefreshControl的功能仅是使用滚动视图时很有用; 这就是为什么这种方法应该更明显地设置刷新控制视图.

但是,您仍然可以选择使用addSubview基于iOS版本:

if #available(iOS 10.0, *) {
  collectionView.refreshControl = refreshControl
} else {
  collectionView.addSubview(refreshControl)
}
Run Code Online (Sandbox Code Playgroud)

  • `doSomething` 应该是 `@objc func` (4认同)

Gil*_*man 44

斯威夫特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 reload tableView
}
Run Code Online (Sandbox Code Playgroud)

你可以停止刷新:

refreshControl.endRefreshing()
Run Code Online (Sandbox Code Playgroud)


Gur*_*ngh 8

斯威夫特 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
    }
Run Code Online (Sandbox Code Playgroud)


Zai*_*han 7

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()
}
Run Code Online (Sandbox Code Playgroud)


Lev*_*rin 5

安希尔的回答对我很有帮助.

但是,经过进一步的实验,我注意到建议的解决方案有时会导致一个不那么漂亮的UI故障.

相反,采用这种方法*为我做了诀窍.

*Swift 2.1

//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
Run Code Online (Sandbox Code Playgroud)


Vas*_*huk 5

细节

  • Xcode 版本 10.3 (10G8)、Swift 5

特征

  • 能够以编程方式进行“拉动刷新”
  • 防止多重“拉动刷新”事件
  • 能够在视图控制器切换时继续活动指示器的动画(例如,在 TabController 的情况下)

解决方案

import UIKit

class RefreshControl: UIRefreshControl {

    private weak var actionTarget: AnyObject?
    private var actionSelector: Selector?
    override init() { super.init() }

    convenience init(actionTarget: AnyObject?, actionSelector: Selector) {
        self.init()
        self.actionTarget = actionTarget
        self.actionSelector = actionSelector
        addTarget()
    }

    private func addTarget() {
        guard let actionTarget = actionTarget, let actionSelector = actionSelector else { return }
        addTarget(actionTarget, action: actionSelector, for: .valueChanged)
    }

    required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }

    func endRefreshing(deadline: DispatchTime? = nil) {
        guard let deadline = deadline else { endRefreshing(); return }
        DispatchQueue.global(qos: .default).asyncAfter(deadline: deadline) { [weak self] in
            DispatchQueue.main.async { self?.endRefreshing() }
        }
    }

    func refreshActivityIndicatorView() {
        guard let selector = actionSelector else { return }
        let _isRefreshing = isRefreshing
        removeTarget(actionTarget, action: selector, for: .valueChanged)
        endRefreshing()
        if _isRefreshing { beginRefreshing() }
        addTarget()
    }

    func generateRefreshEvent() {
        beginRefreshing()
        sendActions(for: .valueChanged)
    }
}

public extension UIScrollView {

    private var _refreshControl: RefreshControl? { return refreshControl as? RefreshControl }

    func addRefreshControll(actionTarget: AnyObject?, action: Selector, replaceIfExist: Bool = false) {
        if !replaceIfExist && refreshControl != nil { return }
        refreshControl = RefreshControl(actionTarget: actionTarget, actionSelector: action)
    }

    func scrollToTopAndShowRunningRefreshControl(changeContentOffsetWithAnimation: Bool = false) {
        _refreshControl?.refreshActivityIndicatorView()
        guard   let refreshControl = refreshControl,
                contentOffset.y != -refreshControl.frame.height else { return }
        setContentOffset(CGPoint(x: 0, y: -refreshControl.frame.height), animated: changeContentOffsetWithAnimation)
    }

    private var canStartRefreshing: Bool {
        guard let refreshControl = refreshControl, !refreshControl.isRefreshing else { return false }
        return true
    }

    func startRefreshing() {
        guard canStartRefreshing else { return }
        _refreshControl?.generateRefreshEvent()
    }

    func pullAndRefresh() {
        guard canStartRefreshing else { return }
        scrollToTopAndShowRunningRefreshControl(changeContentOffsetWithAnimation: true)
        _refreshControl?.generateRefreshEvent()
    }

    func endRefreshing(deadline: DispatchTime? = nil) { _refreshControl?.endRefreshing(deadline: deadline) }
}
Run Code Online (Sandbox Code Playgroud)

用法

// 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()
Run Code Online (Sandbox Code Playgroud)

完整样本

不要忘记在此处添加解决方案代码

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.delegate = self
        tableView.addRefreshControll(actionTarget: self, action: #selector(refreshData))
        self.tableView = tableView
    }
}

extension ViewController {
    @objc func refreshData(_ refreshControl: UIRefreshControl) {
        print("refreshing")
        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
    }
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.pullAndRefresh()
    }
}
Run Code Online (Sandbox Code Playgroud)