UIRefreshControl sin UITableViewController

Es curioso, ya que no parece posible de inmediato, pero ¿hay alguna manera furtiva de aprovechar la nueva clase iOS 6 UIRefreshControl sin usar una subclase UITableViewController ?

A menudo utilizo un UIViewController con una subvista UITableViewDataSource y UITableViewDelegate UITableViewDataSource a UITableViewDataSource y UITableViewDelegate lugar de utilizar un UITableViewController completo.

En una corazonada, y en base a la inspiración de DrummerB, intenté simplemente agregar una instancia de UIRefreshControl como una subvista a mi UITableView . ¡Y mágicamente simplemente funciona!

 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged]; [self.myTableView addSubview:refreshControl]; 

Esto agrega un UIRefreshControl sobre su vista de tabla y funciona como se espera sin tener que usar un UITableViewController 🙂


EDITAR: Esto anterior todavía funciona, pero como algunos han señalado, hay un ligero “tartamudeo” cuando se agrega el UIRefreshControl de esta manera. Una solución para eso es crear una instancia de UITableViewController, y luego configurar su UIRefreshControl y UITableView, es decir:

 UITableViewController *tableViewController = [[UITableViewController alloc] init]; tableViewController.tableView = self.myTableView; self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged]; tableViewController.refreshControl = self.refreshControl; 

Para eliminar el tartamudeo provocado por la respuesta aceptada, puede asignar su UITableView a UITableViewController .

 _tableViewController = [[UITableViewController alloc]initWithStyle:UITableViewStylePlain]; [self addChildViewController:_tableViewController]; _tableViewController.refreshControl = [UIRefreshControl new]; [_tableViewController.refreshControl addTarget:self action:@selector(loadStream) forControlEvents:UIControlEventValueChanged]; _theTableView = _tableViewController.tableView; 

EDITAR:

Una forma de agregar un UIRefreshControl sin UITableViewController sin tartamudear y conservar la animación agradable después de actualizar los datos en la tabla vista.

 UIRefreshControl *refreshControl = [UIRefreshControl new]; [refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged]; [self.theTableView addSubview:refreshControl]; [self.theTableView sendSubviewToBack:refreshControl]; 

Más tarde al manejar los datos actualizados …

 - (void)handleRefresh:(UIRefreshControl *)refreshControl { [self.theTableView reloadData]; [self.theTableView layoutIfNeeded]; [refreshControl endRefreshing]; } 

Lo que intentarías es usar la vista contenedor dentro de ViewController que estás usando. puede definir la subclase limpia UITableViewController con vista de tabla dedicada y colocarla en ViewController.

Bueno, UIRefreshControl es una subclase de UIView, por lo que puedes usarla solo. No estoy seguro de cómo se representa a sí mismo. La representación podría depender simplemente del marco, pero también podría depender de UIScrollView o UITableViewController.

De cualquier manera, va a ser más un truco que una solución elegante. Te recomiendo que busques uno de los clones de terceros disponibles o que escribas el tuyo.

ODRefreshControl

enter image description here

SlimeRefresh

enter image description here

Intente demorar la llamada al método refreshControl -endRefresh por una fracción de segundo después de que tableView vuelva a cargar su contenido, ya sea mediante el uso de NSObject -performSelector:withObject:afterDelay: o el dispatch_after de GCD.

Creé una categoría en UIRefreshControl para esto:

 @implementation UIRefreshControl (Delay) - (void)endRefreshingAfterDelay:(NSTimeInterval)delay { dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self endRefreshing]; }); } @end 

Lo probé y esto también funciona en Vistas de Colección. Me di cuenta de que una demora tan pequeña como 0.01 segundos es suficiente:

 // My data refresh process here while the refresh control 'isRefreshing' [self.tableView reloadData]; [self.refreshControl endRefreshingAfterDelay:.01]; 

IOS 10 Swift 3.0

es sencillo

 import UIKit class ViewControllerA: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var myTableView: UITableView! override func viewDidLoad() { super.viewDidLoad() myTableView.delegate = self myTableView.dataSource = self if #available(iOS 10.0, *) { let refreshControl = UIRefreshControl() let title = NSLocalizedString("PullToRefresh", comment: "Pull to refresh") refreshControl.attributedTitle = NSAttributedString(string: title) refreshControl.addTarget(self, action: #selector(refreshOptions(sender:)), for: .valueChanged) myTableView.refreshControl = refreshControl } } @objc private func refreshOptions(sender: UIRefreshControl) { // Perform actions to refresh the content // ... // and then dismiss the control sender.endRefreshing() } // MARK: - Table view data source func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 12 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) cell.textLabel?.text = "Cell \(String(indexPath.row))" return cell } } 

enter image description here

Si quieres aprender sobre iOS 10 UIRefreshControl, lee aquí .

Agregar el control de actualización como una subvista crea un espacio vacío encima de los encabezados de sección.

En cambio, incrusté UITableViewController en mi UIViewController, luego cambié mi propiedad tableView para apuntar hacia la incrustada, ¡y viola! Cambios mínimos de código. 🙂

Pasos:

  1. Cree un UITableViewController nuevo en Storyboard e incrústelo en su UIViewController original
  2. Reemplace @IBOutlet weak var tableView: UITableView! con el del UITableViewController recién incorporado, como se muestra a continuación

 class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() let tableViewController = self.childViewControllers.first as! UITableViewController tableView = tableViewController.tableView tableView.dataSource = self tableView.delegate = self // Now we can (properly) add the refresh control let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: "handleRefresh:", forControlEvents: .ValueChanged) tableViewController.refreshControl = refreshControl } ... } 

Para Swift 2.2.

Primero crea UIRefreshControl ().

 var refreshControl : UIRefreshControl! 

En tu método viewDidLoad () agrega:

 refreshControl = UIRefreshControl() refreshControl.attributedTitle = NSAttributedString(string: "Refreshing..") refreshControl.addTarget(self, action: #selector(YourUIViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged) self.tableView.addSubview(refreshControl) 

Y hacer que la función de actualización

 func refresh(refreshControl: UIRefreshControl) { // do something ... // reload tableView self.tableView.reloadData() // End refreshing refreshControl.endRefreshing() } 

Aquí hay otra solución que es un poco diferente.

Tuve que usarlo debido a algunos problemas de jerarquía de vista que tenía: estaba creando una funcionalidad que requería pasar vistas a diferentes lugares en la jerarquía de vistas, que se rompió al usar tableview de UITableViewController b / c tableView es la vista raíz de UITableViewController ( self.view) y no solo una vista normal, creó jerarquías inconsistentes de controlador / vista y provocó un locking.

Básicamente, cree su propia subclase de UITableViewController y anule loadView para asignar self.view a una vista diferente, y anule la propiedad tableView para devolver una tabla vista separada.

por ejemplo:

 @interface MyTableVC : UITableViewController @end @interface MyTableVC () @property (nonatomic, strong) UITableView *separateTableView; @end @implementation MyTableVC - (void)loadView { self.view = [[UIView alloc] initWithFrame:CGRectZero]; } - (UITableView *)tableView { return self.separateTableView; } - (void)setTableView:(UITableView *)tableView { self.separateTableView = tableView; } @end 

Cuando se combina con la solución de Keller, esto será más robusto en el sentido de que tableView ahora es una vista normal, no una vista de raíz de VC, y será más robusto frente a las jerarquías de vista cambiantes. Ejemplo de usarlo de esta manera:

 MyTableVC *tableViewController = [[MyTableVC alloc] init]; tableViewController.tableView = self.myTableView; self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged]; tableViewController.refreshControl = self.refreshControl; 

Hay otro uso posible para esto:

Como la creación de subclases de esta manera separa self.view de self.tableView, ahora es posible usar este UITableViewController como un controlador regular y agregar otras subvistas a self.view sin las rarezas de agregar subvistas a UITableView, por lo que uno puede considerar hacer su ver los controladores directamente una subclase de UITableViewController en lugar de tener UITableViewController hijos.

Algunas cosas para tener en cuenta:

Ya que estamos anulando la propiedad tableView sin llamar a super, puede haber algunas cosas de las que hay que tener cuidado y que se deben manejar cuando sea necesario. Por ejemplo, establecer la vista de tabla en el ejemplo anterior no agregará la vista de tabla a self.view y no establecerá el marco que puede querer hacer. Además, en esta implementación no se le proporciona tableView por defecto cuando se crea una instancia de la clase, que también es algo que puede considerar agregar. No lo incluyo aquí porque eso es caso por caso, y esta solución en realidad encaja bien con la solución de Keller.

Prueba esto,

Las soluciones anteriores están bien, pero tableView.refreshControl está disponible solo para UITableViewController, hasta iOS 9.x y viene en UITableView desde iOS 10.x en adelante.

Escrito en Swift 3 –

 let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: #selector(FeedViewController.loadNewData), for: UIControlEvents.valueChanged) // Fix for the RefreshControl Not appearing in background tableView?.addSubview(refreshControl) tableView.sendSubview(toBack: refreshControl) 

La primera sugerencia de Keller provoca un extraño error en iOS 7 donde el recuadro de la tabla aumenta después de que reaparece el controlador de vista. Cambiando a la segunda respuesta, usando el controlador de uitableview, arreglado cosas para mí.

Resulta que puede usar lo siguiente cuando usa un UIViewController con una subvista UITableView y cumple con UITableViewDataSource y UITableViewDelegate:

 self.refreshControl = [[UIRefreshControl alloc]init]; [self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];