Как использовать pull для обновления в Swift?

Я создаю RSS-ридер, используя swift, и вам нужно реализовать функцию pull для перезагрузки.

Вот как я пытаюсь это сделать.

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()
}

Я получаю:

Свойство self.refresh не инициализировано при вызове super.init

Пожалуйста, помогите мне понять поведение распознавателей Gesture. Рабочий образец кода будет большой помощью.

Спасибо.

Ответ 1

Pull для обновления встроен в 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()

Ответ 2

Решение с раскадровкой и быстрой...

1.) Откройте файл .storyboard, выберите TableViewController в раскадровке и "Включите" контроллер табличного представления - функция обновления в утилитах.

enter image description here

2.) Откройте связанный UITableViewController-Class и добавьте следующую строку в viewDidLoad-Method.

self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)

Отредактировано для Swift 5.0:

self.refreshControl?.addTarget(self, action: #selector(refresh), for: UIControl.Event.valueChanged)

ИЛИ в Swift 2.2:

self.refreshControl?.addTarget(self, action: #selector(TestTableViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)

3.) Добавьте следующий метод выше метода viewDidLoad

func refresh(sender:AnyObject)
{
    // Updating your data here...

    self.tableView.reloadData()
    self.refreshControl?.endRefreshing()
}

Ответ 3

iOS 10 - Swift 3 (также применимо для iOS 11 - Swift 4)

Я хотел бы упомянуть функцию PRETTY COOL, которая была включена с iOS 10, а именно:

На данный момент UIRefreshControl напрямую поддерживается в каждом из UICollectionView, UITableView и UIScrollView !

Каждое из этих представлений имеет свойство экземпляра 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 полезно при работе с прокруткой; Вот почему этот подход должен быть более очевидным для настройки представления управления обновлением.

Тем не менее, у вас все еще есть возможность использовать addSubview зависимости от версии iOS:

if #available(iOS 10.0, *) {
  collectionView.refreshControl = refreshControl
} else {
  collectionView.addSubview(refreshControl)
}

Ответ 4

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 reload tableView
}

И вы можете перестать обновляться с помощью:

refreshControl.endRefreshing()

Ответ 5

В 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

Ответ Anhil мне очень помог.

Однако, после дальнейших экспериментов я заметил, что предлагаемое решение иногда вызывает не очень красивый пользовательский интерфейс.

Вместо этого, для этого подхода * помогло.

* 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

Ответ 7

Что говорит вам об ошибке: refresh не инициализируется. Обратите внимание, что вы решили сделать refresh необязательным, что в Swift означает, что оно должно иметь значение, прежде чем вы вызовете super.init (или он неявно называется, что похоже на ваш случай). Либо сделайте refresh необязательным (возможно, что вы хотите), либо инициализируете его каким-либо образом.

Я бы посоветовал снова прочитать вводную документацию Swift, которая охватывает это в значительной степени.

Последнее, а не часть ответа, на что указывает @Anil, есть встроенный механизм для обновления в iOS под названием UIRefresControl, который может быть интересным.

Ответ 8

Я построил приложение для RSS-канала, в котором у меня есть функция Pull To Refresh, в которой изначально были некоторые из перечисленных выше проблем.

Но чтобы добавить к ответам пользователей выше, я везде искал свой вариант использования и не мог его найти. Я загружал данные из Интернета (RSSFeed), и я хотел снять с моего стола таблицы историй для обновления.

То, что упомянуто выше, охватывает правильные области, но с некоторыми проблемами, которые возникают у людей, вот что я сделал, и это работает:

Я взял подход @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()
}

Ответ 9

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

Я предлагаю сделать расширение pull to Refresh для использования в каждом классе.

1) Сделайте пустой быстрый файл: 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) В вашем контроллере просмотра вызовите эти методы как:

  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

Если вы хотите обновить, я использую

DGElasticPullToRefresh

https://github.com/gontovnik/DGElasticPullToRefresh

Установка

pod 'DGElasticPullToRefresh'

import DGElasticPullToRefresh

и поместите эту функцию в ваш быстрый файл и вызовите это funtion из

переопределить 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

Подробнее

  • Версия Xcode 10.3 (10G8), Swift 5

Особенности

  • Возможность сделать "тянуть, чтобы обновить" программно
  • Защита от multi- событий "тянуть, чтобы обновить"
  • Возможность продолжить анимацию индикатора активности при переключении контроллера представления (например, в случае 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) }
}

Usage

Usage
// 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.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()
    }
}

Ответ 13

вы можете использовать этот подкласс 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 - в построителе интерфейса измените класс tableView на PullToRefreshTableView или создайте PullToRefreshTableView программно

2 - реализовать PullToRefreshTableViewDelegate в вашем контроллере просмотра

3 - tableViewDidStartRefreshing(tableView: PullToRefreshTableView) будет вызываться в вашем контроллере просмотра, когда представление таблицы начнет обновляться

4 - вызов yourTableView.endRefreshing(), чтобы завершить обновление

Ответ 14

Вот как я сделал это, используя 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, после чего последующие обновления будут работать нормально.

Ответ 15

Вы можете достичь этого, используя несколько строк кода. Итак, почему вы собираетесь застрять в сторонней библиотеке или пользовательском интерфейсе. Pull для обновления встроен в iOS. Вы можете сделать это в кратчайшие сроки, как

enter image description here

var pullControl = UIRefreshControl()

override func viewDidLoad() {
   super.viewDidLoad()

   pullControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
   pullControl.addTarget(self, action: #selector(pulledRefreshControl(_:)), for: UIControl.Event.valueChanged)
   tableView.addSubview(pullControl) // not required when using UITableViewController
}

@objc func pulledRefreshControl(sender:AnyObject) {
   // Code to refresh table view  
}

Ответ 16

Другие ответы правильны, но для получения дополнительной информации проверьте это сообщение Pull to Refresh

Включить обновление в раскадровке

Когда вы работаете с 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)
}
  • Так как Ive задал "handleRefresh:" (обратите внимание на двоеточие!) как аргумент действия, мне нужно определить функцию в этом Класс UITableViewController с тем же именем. Кроме того, функция должна принимать один аргумент
  • Ср. как это действие, которое нужно вызвать для вызываемого UIControlEvent ValueChanged
  • Не забудьте позвонить refreshControl.endRefreshing()

Для получения дополнительной информации, пожалуйста, перейдите к ссылке, и все кредиты будут отправлены на этот пост.