web-dev-qa-db-fra.com

UIRefreshControl sans UITableViewController

Curieux, cela ne semble pas immédiatement possible, mais existe-t-il un moyen sournois de tirer parti de la nouvelle classe iOS 6 UIRefreshControl sans utiliser de sous-classe UITableViewController?

J'utilise souvent un UIViewController avec un UITableView et je me conforme à UITableViewDataSource et UITableViewDelegate plutôt que d'utiliser un UITableViewController.

305
Keller

Inspiré de DrummerB, j’ai simplement essayé d’ajouter une instance UIRefreshControl en tant que sous-vue de mon UITableView. Et cela fonctionne comme par magie!

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

Cela ajoute un UIRefreshControl au-dessus de la vue de votre table et fonctionne comme prévu sans avoir à utiliser un UITableViewController :)


EDIT: Ceci ci-dessus fonctionne toujours, mais comme quelques-uns l’ont signalé, il y a un léger "bégaiement" lorsqu’on ajoute le UIRefreshControl de cette manière. Une solution consiste à instancier un UITableViewController, puis à définir votre UIRefreshControl et votre UITableView, c’est-à-dire:

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;
386
Keller

Pour éliminer le bégaiement causé par la réponse acceptée, vous pouvez affecter votre UITableView à un 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;

EDIT:

Une façon d'ajouter une UIRefreshControl sans UITableViewController sans bégayer et de conserver l'animation de Nice après l'actualisation des données dans la vue de table.

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

Plus tard, lors du traitement des données actualisées ...

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

Ce que vous voudriez essayer, c’est d’utiliser la vue conteneur dans ViewController que vous utilisez. vous pouvez définir une sous-classe propre UITableViewController avec une vue de table dédiée et la placer dans ViewController.

21
Tomohisa Takaoka

Eh bien, UIRefreshControl est une sous-classe UIView, vous pouvez donc l'utiliser seule. Je ne sais pas comment ça se rend. Le rendu pourrait simplement dépendre du cadre, mais il pourrait également s'appuyer sur UIScrollView ou UITableViewController.

Dans les deux cas, ce sera plus un bidouillage qu'une solution élégante. Je vous recommande d’examiner un des clones tiers disponibles ou d’écrire le vôtre.

ODRefreshControl

enter image description here

SlimeRefresh

enter image description here

18
DrummerB

Essayez de retarder l'appel de la méthode refreshControl -endRefresh d'une fraction de seconde après le chargement du tableau dans son contenu, soit à l'aide de -performSelector:withObject:afterDelay: de NSObject, soit de dispatch_after de GCD.

J'ai créé une catégorie sur UIRefreshControl pour cela:

@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

Je l'ai testé et cela fonctionne également sur les vues de collection. J'ai remarqué qu'un délai aussi petit que 0,01 seconde est suffisant:

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

IOS 10 Swift 3.0

c'est simple

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 vous souhaitez en savoir plus sur iOS 10 UIRefreshControl, lisez ici .

6
Ashok R

L'ajout du contrôle d'actualisation en tant que sous-vue crée un espace vide au-dessus des en-têtes de section.

Au lieu de cela, j'ai incorporé un UITableViewController dans mon UIViewController, puis modifié ma propriété tableView pour qu'elle pointe vers celui qui est incorporé, et alto! Changements de code minimaux. :-)

Pas:

  1. Créez un nouveau UITableViewController dans Storyboard et intégrez-le dans votre UIViewController d'origine.
  2. Remplacez @IBOutlet weak var tableView: UITableView! par celui du nouveau UITableViewController, comme indiqué ci-dessous.

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
    }

    ...
}
3
cbh2000

Pour Swift 2.2.

Commencez par créer UIRefreshControl ().

var refreshControl : UIRefreshControl!

Dans votre méthode viewDidLoad (), ajoutez:

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

Et rendre la fonction de rafraîchissement

func refresh(refreshControl: UIRefreshControl) {

    // do something ...

    // reload tableView
    self.tableView.reloadData()

    // End refreshing
    refreshControl.endRefreshing()
}
2
stakahop

Essaye ça,

Les solutions ci-dessus conviennent, mais tableView.refreshControl est disponible uniquement pour UITableViewController, jusqu'à iOS 9.x et dans UITableView à partir de iOS 10.x.

Écrit 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)
0
Ankit Kumar Gupta

Voici une autre solution qui est un peu différente.

Je devais l'utiliser à cause de certains problèmes de hiérarchie de vues: je créais certaines fonctionnalités qui nécessitaient de transmettre des vues à différents endroits de la hiérarchie, interrompues lors de l'utilisation d'une vue de table UITableViewController car la vue de table était la vue racine de UITableViewController ( auto.view) et pas seulement une vue régulière, il a créé des hiérarchies de contrôleur/vue incohérentes et a provoqué un blocage.

Fondamentalement, créez votre propre sous-classe UITableViewController et substituez loadView pour attribuer à self.view une vue différente et substituez la propriété tableView pour renvoyer une vue table séparée.

par exemple:

@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

Combinée à la solution de Keller, elle devient plus robuste, en ce sens que la tableView est désormais une vue normale, et non une vue racine de VC, et plus robuste face aux hiérarchies de vues changeantes. Exemple d'utilisation de cette façon:

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;

Il y a une autre utilisation possible pour cela:

Comme cette sous-classe sépare self.view de self.tableView, il est maintenant possible d’utiliser ce UITableViewController en tant que contrôleur normal et d’ajouter d’autres sous-vues à self.view sans les particularités de l’ajout de sous-vues à UITableView. affichez les contrôleurs directement dans une sous-classe de UITableViewController au lieu d’avoir des enfants UITableViewController.

Quelques points à surveiller:

Étant donné que nous ignorons la propriété tableView sans appeler super, il peut y avoir certaines choses à surveiller et à gérer si nécessaire. Par exemple, la définition de la table dans l'exemple ci-dessus n'ajoute pas la table à self.view et ne définit pas le cadre que vous souhaitez peut-être modifier. De plus, dans cette implémentation, aucune tableView par défaut ne vous est fournie lorsque la classe est instanciée, ce que vous pouvez également envisager d'ajouter. Je ne l'inclus pas ici parce que c'est au cas par cas, et cette solution correspond bien à la solution de Keller.

0
psilencer