Ich baue einen RSS-Reader mit Swift und muss Pull implementieren, um die Funktionalität neu zu laden.
So versuche ich es zu tun.
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()
}
Ich bekomme :
Die Eigenschaft 'self.refresh' wurde beim Aufruf von super.init nicht initialisiert
Bitte helfen Sie mir, das Verhalten von Gestenerkennern zu verstehen. Ein funktionierender Beispielcode ist eine große Hilfe.
Vielen Dank.
Zum Aktualisieren ziehen ist in iOS integriert. Du könntest das in Swift gerne machen
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
}
Irgendwann könnte man die Erfrischung beenden.
refreshControl.endRefreshing()
Eine Lösung mit Storyboard und Swift ...
1.) Öffnen Sie die .storyboard-Datei, wählen Sie einen TableViewController in Ihrem Storyboard aus und aktivieren Sie die Funktion TableView Controller - Refreshing in den Dienstprogrammen.
2.) Öffnen Sie die zugehörige UITableViewController-Klasse und fügen Sie die folgende Zeile in die viewDidLoad-Methode ein.
self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
ODERin Swift 2.2:
self.refreshControl?.addTarget(self, action: #selector(TestTableViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
3.) Fügen Sie die folgende Methode über der viewDidLoad-Methode hinzu
func refresh(sender:AnyObject)
{
// Updating your data here...
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
Ich möchte eine PRETTY COOL - Funktion erwähnen, die seit iOS 10 enthalten ist.
Für jetzt wird UIRefreshControl direkt in jeder von UICollectionView
, UITableView
und UIScrollView
unterstützt!
Jede dieser Ansichten hat refreshControl instance -Eigenschaft, was bedeutet, dass Sie müssen es nicht mehr als Unteransicht in Ihrer Bildlaufansicht hinzufügen
@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()
}
Ich persönlich finde es natürlicher, es als eine Eigenschaft für die Bildlaufansicht zu behandeln, anstatt es als Unteransicht hinzuzufügen, insbesondere weil die einzige geeignete Ansicht als Ubersicht für ein UIRefreshControl-Objekt eine Bildlaufansicht ist nützlich bei der Arbeit mit einer Bildlaufansicht; Aus diesem Grund sollte dieser Ansatz offensichtlicher sein, um die Aktualisierungssteuerungsansicht einzurichten.
Sie haben jedoch immer noch die Möglichkeit, die addSubview
basierend auf der iOS-Version zu verwenden:
if #available(iOS 10.0, *) {
collectionView.refreshControl = refreshControl
} else {
collectionView.addSubview(refreshControl)
}
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
}
Und Sie könnten aufhören zu erfrischen mit:
refreshControl.endRefreshing()
In Swift benutze das,
Wenn Sie möchten, dass Pull in WebView aktualisiert wird,
Also versuche diesen Code:
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()
}
Anhils Antwort hat mir sehr geholfen.
Nach weiterem Experimentieren bemerkte ich jedoch, dass die vorgeschlagene Lösung manchmal eine nicht so hübsche UI-Störung verursacht.
Stattdessen habe ich diesen Ansatz * gewählt.
//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
Der Fehler sagt Ihnen, dass refresh
nicht initialisiert wird. Beachten Sie, dass Sie refresh
nicht optional machen, was in Swift bedeutet, dass haseinen Wert hat, bevor Sie super.init
aufrufen (oder implizit aufgerufen wird, was in Ihrem Fall der Fall zu sein scheint). Machen Sie entweder refresh
optional (wahrscheinlich, was Sie möchten) oder initialisieren Sie es irgendwie.
Ich würde vorschlagen, die Swift-Einführungsdokumentation erneut zu lesen, die dies ausführlich behandelt.
Eine letzte Sache, die nicht Teil der Antwort ist, wie von @Anil hervorgehoben, ist eine eingebaute Pull-Aktualisierungssteuerung in iOS mit dem Namen UIRefresControl
, die möglicherweise einen Blick wert ist.
Ich habe eine RSS-Feed-App erstellt, in der ich eine Pull To Refresh-Funktion habe, die ursprünglich einige der oben aufgeführten Probleme hatte.
Aber zu den obigen Antworten der Benutzer habe ich überall nach meinem Anwendungsfall gesucht und konnte ihn nicht finden. Ich habe Daten aus dem Internet heruntergeladen (RSSFeed) und wollte meine TableView der zu aktualisierenden Stories nach unten ziehen.
Was oben erwähnt wurde, umfasst die richtigen Bereiche, aber mit einigen Problemen, die die Leute haben, habe ich Folgendes getan und es funktioniert sehr gut:
Ich habe @Blankarschs Ansatz gewählt, bin zu meinem main.storyboard gegangen und habe die Tabellensicht zum Aktualisieren gewählt. Was nicht erwähnt wurde, ist das Erstellen von IBOutlet und IBAction, um die Aktualisierung effizient zu verwenden
//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()
}
Ich hoffe, das hilft jedem, der sich in derselben Situation wie ich befindet
Ich empfehle eine Erweiterung von Pull To Refresh, die in jeder Klasse verwendet werden kann.
1) Machen Sie eine leere Swift-Datei: Datei - Neu - Datei - Swift-Datei.
2) Fügen Sie Folgendes hinzu
// 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) Rufen Sie in Ihrem View Controller diese Methoden auf als:
override func viewWillAppear(animated: Bool) {
self.makePullToRefreshToTableView(bidderListTable, triggerToMethodName: "pullToRefreshBidderTable")
}
4) Irgendwann wollten Sie die Aktualisierung beenden:
func pullToRefreshBidderTable() {
self.makePullToRefreshEndRefreshing("bidderListTable")
//Code What to do here.
}
OR
self.makePullToRefreshEndRefreshing("bidderListTable")
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) }
}
// 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()
Vergessen Sie nicht fügen Sie den Lösungscode hier hinz
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()
}
}
sie können diese Unterklasse von tableView verwenden:
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 - im Interface Builder ändern Sie die Klasse Ihrer tableView in PullToRefreshTableView
oder erstellen Sie PullToRefreshTableView
programmgesteuert
2 - Implementieren Sie die PullToRefreshTableViewDelegate
in Ihrem View-Controller
3 - tableViewDidStartRefreshing(tableView: PullToRefreshTableView)
wird in Ihrem View-Controller aufgerufen, wenn die Aktualisierung der Tabellenansicht beginnt
4 - Rufen Sie yourTableView.endRefreshing()
auf, um die Aktualisierung zu beenden
Für den Pull zum Aktualisieren verwende ich
DGElasticPullToRefresh
https://github.com/gontovnik/DGElasticPullToRefresh
Installation
pod 'DGElasticPullToRefresh'
import DGElasticPullToRefresh
und fügen Sie diese Funktion in Ihre Swift-Datei ein und rufen Sie diese Funktion von Ihrem auf
override func viewWillAppear (_ animiert: 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!)
}
Und vergessen Sie nicht, die Referenz zu entfernen, während die Ansicht verschwindet
zum Entfernen von Pull zum Aktualisieren fügen Sie diesen Code in Ihr ein
override func viewDidDisappear (_ animiert: Bool)
override func viewDidDisappear(_ animated: Bool) {
table.dg_removePullToRefresh()
}
Und es sieht so aus
Viel Spaß beim Codieren :)
So habe ich es mit Xcode 7.2 zum Laufen gebracht, was meiner Meinung nach ein schwerwiegender Fehler ist. Ich verwende es in meiner UITableViewController
in meiner viewWillAppear
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: "configureMessages", forControlEvents: .ValueChanged)
refreshControl!.beginRefreshing()
configureMessages()
func configureMessages() {
// configuring messages logic here
self.refreshControl!.endRefreshing()
}
Wie Sie sehen können, muss ich die configureMessage()
-Methode nach dem Einrichten meiner UIRefreshControl
buchstäblich aufrufen. Danach funktionieren nachfolgende Aktualisierungen einwandfrei.
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()
}