142 votes

Gestion d'un UITableView vide. Imprimer un message amical

J'ai un UITableView qui, dans certains cas, peut être vide. Ainsi, au lieu d'afficher l'image l'image d'arrière-plan de l'application, je préférerais imprimer un message amical dans l'écran, tel que :

Cette liste est maintenant vide

Quelle est la manière la plus simple de le faire ?

195voto

Ray Fix Points 1418

La propriété backgroundView de UITableView est votre amie.

Sur viewDidLoad ou n'importe quel endroit où vous reloadData vous devez déterminer si votre tableau est vide ou non et mettre à jour la propriété backgroundView de l'UITableView avec un UIView contenant un UILabel ou simplement lui attribuer la valeur nil. C'est tout.

Il est bien sûr possible de faire en sorte que la source de données de UITableView fasse double emploi et renvoie une cellule spéciale "liste vide", mais cela me semble être une astuce. Soudain, numberOfRowsInSection:(NSInteger)section doit calculer le nombre de lignes des autres sections pour lesquelles il n'a pas été interrogé, afin de s'assurer qu'elles sont également vides. Vous devez également créer une cellule spéciale qui contient le message vide. N'oubliez pas non plus que vous devrez probablement modifier la hauteur de votre cellule pour tenir compte du message vide. Tout cela est faisable, mais cela ressemble à du sparadrap sur du sparadrap.

122voto

Frankie Points 6440

Même chose que la réponse de Jhonston, mais je l'ai préféré en tant qu'extension :

import UIKit

extension UITableView {

    func setEmptyMessage(_ message: String) {
        let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height))
        messageLabel.text = message
        messageLabel.textColor = .black
        messageLabel.numberOfLines = 0
        messageLabel.textAlignment = .center
        messageLabel.font = UIFont(name: "TrebuchetMS", size: 15)
        messageLabel.sizeToFit()

        self.backgroundView = messageLabel
        self.separatorStyle = .none
    }

    func restore() {
        self.backgroundView = nil
        self.separatorStyle = .singleLine
    }
}

Utilisation :

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if things.count == 0 {
        self.tableView.setEmptyMessage("My Message")
    } else {
        self.tableView.restore()
    }

    return things.count
}

90voto

Johnston Points 1476

Sur la base des réponses ici, voici un cours rapide que j'ai fait et que vous pouvez utiliser dans votre UITableViewController .

import Foundation
import UIKit

class TableViewHelper {

    class func EmptyMessage(message:String, viewController:UITableViewController) {
        let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height))
        let messageLabel = UILabel(frame: rect)
        messageLabel.text = message
        messageLabel.textColor = UIColor.blackColor()
        messageLabel.numberOfLines = 0;
        messageLabel.textAlignment = .Center;
        messageLabel.font = UIFont(name: "TrebuchetMS", size: 15)
        messageLabel.sizeToFit()

        viewController.tableView.backgroundView = messageLabel;
        viewController.tableView.separatorStyle = .None;
    }
}

Dans votre UITableViewController vous pouvez l'appeler dans numberOfSectionsInTableView(tableView: UITableView) -> Int

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    if projects.count > 0 {
        return 1
    } else {
        TableViewHelper.EmptyMessage("You don't have any projects yet.\nYou can create up to 10.", viewController: self)
        return 0
    }
}

enter image description here

Avec un peu d'aide de http://www.appcoda.com/pull-to-refresh-uitableview-empty/

18voto

Hapeki Points 1055

Je recommande la bibliothèque suivante : DZNEmptyDataSet

La façon la plus simple de l'ajouter dans votre projet est de l'utiliser avec Cocaopods comme ceci : pod 'DZNEmptyDataSet'

Dans votre TableViewController, ajoutez l'instruction d'importation suivante (Swift) :

import DZNEmptyDataSet

Ensuite, assurez-vous que votre classe est conforme à la DNZEmptyDataSetSource y DZNEmptyDataSetDelegate comme ça :

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

Dans votre viewDidLoad ajoutez les lignes de code suivantes :

tableView.emptyDataSetSource = self
tableView.emptyDataSetDelegate = self
tableView.tableFooterView = UIView()

Maintenant, tout ce que vous avez à faire pour montrer l'état vide est :

//Add title for empty dataset
func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
    let str = "Welcome"
    let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)]
    return NSAttributedString(string: str, attributes: attrs)
}

//Add description/subtitle on empty dataset
func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
    let str = "Tap the button below to add your first grokkleglob."
    let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleBody)]
    return NSAttributedString(string: str, attributes: attrs)
}

//Add your image
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
    return UIImage(named: "MYIMAGE")
}

//Add your button 
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
    let str = "Add Grokkleglob"
    let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleCallout)]
    return NSAttributedString(string: str, attributes: attrs)
}

//Add action for button
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
    let ac = UIAlertController(title: "Button tapped!", message: nil, preferredStyle: .Alert)
    ac.addAction(UIAlertAction(title: "Hurray", style: .Default, handler: nil))
    presentViewController(ac, animated: true, completion: nil)
}

Ces méthodes ne sont pas obligatoires, il est également possible d'afficher simplement l'état vide sans bouton, etc.

Pour Swift 4

// MARK: - Deal with the empty data set
// Add title for empty dataset
func title(forEmptyDataSet _: UIScrollView!) -> NSAttributedString! {
    let str = "Welcome"
    let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)]
    return NSAttributedString(string: str, attributes: attrs)
}

// Add description/subtitle on empty dataset
func description(forEmptyDataSet _: UIScrollView!) -> NSAttributedString! {
    let str = "Tap the button below to add your first grokkleglob."
    let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)]
    return NSAttributedString(string: str, attributes: attrs)
}

// Add your image
func image(forEmptyDataSet _: UIScrollView!) -> UIImage! {
    return UIImage(named: "MYIMAGE")
}

// Add your button
func buttonTitle(forEmptyDataSet _: UIScrollView!, for _: UIControlState) -> NSAttributedString! {
    let str = "Add Grokkleglob"
    let attrs = [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: UIFontTextStyle.callout), NSAttributedStringKey.foregroundColor: UIColor.white]
    return NSAttributedString(string: str, attributes: attrs)
}

// Add action for button
func emptyDataSetDidTapButton(_: UIScrollView!) {
    let ac = UIAlertController(title: "Button tapped!", message: nil, preferredStyle: .alert)
    ac.addAction(UIAlertAction(title: "Hurray", style: .default, handler: nil))
    present(ac, animated: true, completion: nil)
}

11voto

dasblinkenlight Points 264350

Une façon de le faire serait de modifier votre source de données pour qu'elle retourne 1 lorsque le nombre de lignes est égal à zéro, et pour produire une cellule spéciale (peut-être avec un identifiant de cellule différent) dans le fichier tableView:cellForRowAtIndexPath: méthode.

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSInteger actualNumberOfRows = <calculate the actual number of rows>;
    return (actualNumberOfRows  == 0) ? 1 : actualNumberOfRows;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSInteger actualNumberOfRows = <calculate the actual number of rows>;
    if (actualNumberOfRows == 0) {
        // Produce a special cell with the "list is now empty" message
    }
    // Produce the correct cell the usual way
    ...
}

Cela peut devenir quelque peu compliqué si vous avez plusieurs contrôleurs de vue de table que vous devez gérer, car quelqu'un finira par oublier d'insérer un contrôle zéro. Une meilleure approche consiste à créer une implémentation séparée d'un contrôleur de vue de table. UITableViewDataSource qui renvoie toujours une seule ligne avec un message configurable (appelons-le EmptyTableViewDataSource ). Lorsque les données gérées par votre contrôleur de vue de table changent, le code qui gère le changement vérifie si les données sont vides. Si elles ne sont pas vides, définissez votre contrôleur de vue de tableau avec sa source de données habituelle ; sinon, définissez-le avec une instance de l'élément EmptyTableViewDataSource qui a été configuré avec le message approprié.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X