Behandlung einer leeren UITableView. Drucken Sie eine freundliche Nachricht

124

Ich habe eine UITableView, dass es in einigen Fällen legal ist, leer zu sein. Anstatt das Hintergrundbild der App anzuzeigen, möchte ich lieber eine freundliche Nachricht auf dem Bildschirm drucken, z. B.:

Diese Liste ist jetzt leer

Was ist der einfachste Weg, dies zu tun?

cateof
quelle
10
Schauen Sie sich dieses Projekt an: github.com/dzenbot/DZNEmptyDataSet
oleynikd
@oleynikd Danke !!!!!
Luda

Antworten:

173

Die backgroundView-Eigenschaft von UITableView ist Ihr Freund.

An viewDidLoadoder an einer beliebigen Stelle reloadDatasollten Sie feststellen, ob Ihre Tabelle leer ist oder nicht, und die backgroundView-Eigenschaft von UITableView mit einer UIView aktualisieren, die ein UILabel enthält, oder sie einfach auf Null setzen. Das ist es.

Es ist natürlich möglich, die Datenquelle von UITableView zu einer doppelten Aufgabe zu machen und eine spezielle Zelle "Liste ist leer" zurückzugeben, was mir als Kludge erscheint. Plötzlich numberOfRowsInSection:(NSInteger)sectionmuss die Anzahl der Zeilen anderer Abschnitte berechnet werden, nach denen nicht gefragt wurde, um sicherzustellen, dass sie auch leer sind. Sie müssen auch eine spezielle Zelle erstellen, die die leere Nachricht enthält. Vergessen Sie auch nicht, dass Sie wahrscheinlich die Höhe Ihrer Zelle ändern müssen, um die leere Nachricht aufzunehmen. Das ist alles machbar, aber es scheint wie Pflaster zusätzlich zu Pflaster.

Ray Fix
quelle
12
Die Hintergrundansicht ist meiner Meinung nach die beste Lösung. Danke dir!
Ferran Maylinch
1
Ein Nachteil ist, dass die Nachricht beim Herunterziehen der Tabellenansicht an ihrer Position bleibt. Ich hätte lieber gerne in der App Store App unter Updates. Hier geht die leere Nachricht mit dem Bildlaufverhalten ...
Testen
@testing Wenn Sie zum Scrollen die leere Nachricht benötigen, können Sie die Hintergrundansicht nicht verwenden, da dies nicht Teil der Bildlaufhierarchie ist. Sie möchten wahrscheinlich einen benutzerdefinierten Abschnitt und UITableViewCell für den leeren Status verwenden.
LightningStryk
Das Umschalten von backgroundViewversteckten Eigenschaften ist der richtige Weg. Mit DZNEmptyDataSetmüssen wir seineemptyDataSetSource
onmyway133
Wenn Sie Schaltflächen hinzufügen möchten, müssen Sie Folgendes tun: tableView.backgroundView!.userInteraction = trueNach der Zeile, die Sie festgelegt haben tableView.backgroundView = constructMyViewWithButtons(), oder wie auch immer Sie sie festlegen.
kbpontius
90

Wie Jhonstons Antwort, aber ich habe es als Erweiterung vorgezogen:

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

Verwendung:

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
}
Frankie
quelle
Danke für deinen Vorschlag.
ssowri1
1
Erweiterung ist besser! Vielen Dank.
Ogulcan Orhan
Alix
1
Wenn Sie Abschnitte haben, müssen Sie diese Logik auf die func numberOfSections(in tableView: UITableView) -> IntMethode verschieben
Handwerk
87

Basierend auf den Antworten hier ist hier eine kurze Klasse, die ich gemacht habe und die Sie in Ihrem verwenden können 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;
    }
}

In Ihrem können UITableViewControllerSie dies anrufennumberOfSectionsInTableView(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
    }
}

Geben Sie hier die Bildbeschreibung ein

Mit ein wenig Hilfe von http://www.appcoda.com/pull-to-refresh-uitableview-empty/

Johnston
quelle
möchte aber auch ein Bild hinzufügen. Aber eine tolle schnelle Lösung.
AnBisw
10
Verwenden Sie eine Erweiterung anstelle einer Klasse (übergeben Sie den View Controller nicht)
Cesare
Ich konnte den obigen Code nicht für mich arbeiten lassen, aber ich konnte den Code in dieser Antwort (erste) zum Laufen bringen, falls andere das gleiche Problem haben. Ich denke auch, dass die 2. Antwort auch funktionieren würde (über das Szenendock
Renee Olson
viewController.tableView.separatorStyle = .noneist nicht erforderlich.
Dmitry
17

Ich empfehle die folgende Bibliothek: DZNEmptyDataSet

Der einfachste Weg, es in Ihr Projekt einzufügen, besteht darin, es mit Cocaopods wie folgt zu verwenden: pod 'DZNEmptyDataSet'

Fügen Sie in Ihrem TableViewController die folgende Importanweisung (Swift) hinzu:

import DZNEmptyDataSet

Dann stellen Sie sicher , Ihre Klasse entspricht den DNZEmptyDataSetSourceund in DZNEmptyDataSetDelegateetwa so:

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

Fügen viewDidLoadSie in Ihrem Code die folgenden Codezeilen hinzu:

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

Jetzt müssen Sie nur noch Folgendes tun, um den Emptystate anzuzeigen:

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

Diese Methoden sind nicht obligatorisch, es ist auch möglich, nur den leeren Zustand ohne Schaltfläche usw. anzuzeigen.

Für 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)
}
Hapeki
quelle
Ich habe Probleme damit, dass DZEmptyDataSet nicht richtig vertikal ausgerichtet ist. Hat jemand das gleiche Problem gehabt?
Amariduran
12

Eine Möglichkeit besteht darin, Ihre Datenquelle so zu ändern, dass sie zurückkehrt, 1wenn die Anzahl der Zeilen Null ist, und in der tableView:cellForRowAtIndexPath:Methode eine Spezialzelle (möglicherweise mit einer anderen Zellkennung) zu erstellen .

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

Dies kann etwas kompliziert werden, wenn Sie mehrere Controller für Tabellenansichten haben, die Sie warten müssen, da jemand irgendwann vergisst, eine Nullprüfung einzufügen. Ein besserer Ansatz besteht darin, eine separate Implementierung einer UITableViewDataSourceImplementierung zu erstellen , die immer eine einzelne Zeile mit einer konfigurierbaren Nachricht zurückgibt (nennen wir es EmptyTableViewDataSource). Wenn sich die Daten ändern, die von Ihrem Table View Controller verwaltet werden, prüft der Code, der die Änderung verwaltet, ob die Daten leer sind. Wenn es nicht leer ist, legen Sie Ihren Table View Controller mit seiner regulären Datenquelle fest. Andernfalls legen Sie eine Instanz fest, die EmptyTableViewDataSourcemit der entsprechenden Nachricht konfiguriert wurde.

dasblinkenlight
quelle
5
Ich hatte Probleme mit Tabellen, bei denen Zeilen gelöscht wurden, deleteRowsAtIndexPaths:withRowAnimation:da die von zurückgegebene Nummer numberOfRowsInSectionmit dem Ergebnis von $ numRows - $ rowsDeleted übereinstimmen muss.
Animal451
4
Ich kann es nur wärmstens empfehlen. Es rätselt Ihren Code mit Randfällen.
Xtravar
2
@xtravar Anstatt abzustimmen, sollten Sie Ihre eigene Antwort veröffentlichen.
Dasblinkenlight
1
Ich bin diesen Weg gegangen und es führt zu einer Reihe von Problemen. Nach meiner Erfahrung ist es fast immer besser, Apple-APIs zu erweitern, als sie zu ersetzen.
Xtravar
1
Diese Lösung funktioniert nicht mit NSFetchedResultsController. Ich werde stattdessen den backgroundView-Ansatz ausprobieren.
Sam
10

Ich habe dafür die titleForFooterInSection-Nachricht verwendet. Ich weiß nicht, ob dies nicht optimal ist oder nicht, aber es funktioniert.

-(NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section   {

    NSString *message = @"";
    NSInteger numberOfRowsInSection = [self tableView:self.tableView numberOfRowsInSection:section ];

    if (numberOfRowsInSection == 0) {
        message = @"This list is now empty";
    }

    return message;
}
Carlos B.
quelle
2
Netter Trick und scheint mir ziemlich sauber zu sein. Hier ist ein return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
Einzeiler
8

Für eine sicherere Lösung:

extension UITableView {
func setEmptyMessage(_ message: String) {
    guard self.numberOfRows() == 0 else {
        return
    }
    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.systemFont(ofSize: 14.0, weight: UIFontWeightMedium)
    messageLabel.sizeToFit()

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

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

public func numberOfRows() -> Int {
    var section = 0
    var rowCount = 0
    while section < numberOfSections {
        rowCount += numberOfRows(inSection: section)
        section += 1
    }
    return rowCount
  }
}

und auch für UICollectionView:

extension UICollectionView {
func setEmptyMessage(_ message: String) {
    guard self.numberOfItems() == 0 else {
        return
    }

    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.systemFont(ofSize: 18.0, weight: UIFontWeightSemibold)
    messageLabel.sizeToFit()
    self.backgroundView = messageLabel;
}

func restore() {
    self.backgroundView = nil
}

public func numberOfItems() -> Int {
    var section = 0
    var itemsCount = 0
    while section < self.numberOfSections {
        itemsCount += numberOfItems(inSection: section)
        section += 1
    }
    return itemsCount
  }
}

Generischere Lösung:

    protocol EmptyMessageViewType {
      mutating func setEmptyMessage(_ message: String)
      mutating func restore()
    }

    protocol ListViewType: EmptyMessageViewType where Self: UIView {
      var backgroundView: UIView? { get set }
    }

    extension UITableView: ListViewType {}
    extension UICollectionView: ListViewType {}

    extension ListViewType {
      mutating 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: 16)
        messageLabel.sizeToFit()

        backgroundView = messageLabel
    }

     mutating func restore() {
        backgroundView = nil
     }
}
Meseery
quelle
7

Ich kann nur empfehlen, eine UITextView in die TableView nach den Zellen zu ziehen und dort abzulegen. Stellen Sie eine Verbindung zum ViewController her und blenden Sie ihn gegebenenfalls aus / ein (z. B. wenn die Tabelle neu geladen wird).

Geben Sie hier die Bildbeschreibung ein

pasql
quelle
Das ist der einfachste Weg!
Moonvader
So schmerzhafte Kopfschmerzen auf Apfelart;
Vielen
5

Die Verwendung von backgroundView ist in Ordnung, führt jedoch keinen guten Bildlauf wie in Mail.app durch.

Ich habe etwas ähnliches gemacht wie xtravar .

Ich habe eine Ansicht außerhalb der Ansichtshierarchie des hinzugefügt tableViewController. Hierarchie

Dann habe ich folgenden Code verwendet tableView:numberOfRowsInSection::

if someArray.count == 0 {
    // Show Empty State View
    self.tableView.addSubview(self.emptyStateView)
    self.emptyStateView.center = self.view.center
    self.emptyStateView.center.y -= 60 // rough calculation here
    self.tableView.separatorColor = UIColor.clear
} else if self.emptyStateView.superview != nil {
    // Empty State View is currently visible, but shouldn't
    self.emptyStateView.removeFromSuperview()
    self.tableView.separatorColor = nil
}

return someArray.count

Grundsätzlich habe ich das emptyStateViewals Unteransicht des tableViewObjekts hinzugefügt . Da die Trennzeichen die Ansicht überlappen würden, habe ich ihre Farbe auf eingestellt clearColor. Um zur Standardtrennfarbe zurückzukehren, können Sie sie einfach auf einstellen nil.

mangerlahn
quelle
Das funktioniert ziemlich gut! Wenn Sie jedoch Elemente zum Ziehen haben, um sie zu aktualisieren, wird diese nicht mit ihnen gescrollt. Ich fand es besser, das einzustellen tableHeaderViewund sicherzustellen, dass es die Größe anpasst .
Hannele
4

Laut Apple ist die Verwendung eines Container View Controllers der richtige Weg, dies zu tun .

Ich habe alle meine leeren Statusansichten in einem separaten Storyboard abgelegt. Jedes unter seiner eigenen UIViewController-Unterklasse. Ich füge Inhalte direkt unter ihrer Stammansicht hinzu. Wenn eine Aktion / Schaltfläche erforderlich ist, haben Sie jetzt bereits einen Controller, der dies erledigt.
Dann müssen Sie nur noch den gewünschten Ansichts-Controller von diesem Storyboard aus instanziieren, ihn als untergeordneten Ansichts-Controller hinzufügen und die Container-Ansicht zur Hierarchie der tableView (Unteransicht) hinzufügen. Ihre leere Statusansicht kann ebenfalls gescrollt werden, was sich gut anfühlt und es Ihnen ermöglicht, Pull zum Aktualisieren zu implementieren.

Lesen Sie das Kapitel "Hinzufügen eines untergeordneten View Controllers zu Ihren Inhalten", um Hilfe zur Implementierung zu erhalten.

Stellen Sie einfach sicher, dass Sie den untergeordneten Ansichtsrahmen so einstellen, dass die (0, 0, tableView.frame.width, tableView.frame.height)Dinge zentriert und richtig ausgerichtet werden.

AmitP
quelle
3

Erstens die Probleme mit anderen populären Ansätzen.

Hintergrundansicht

Die Hintergrundansicht ist nicht gut zentriert, wenn Sie den einfachen Fall verwenden, sie als UILabel festzulegen.

Zellen, Kopf- oder Fußzeilen, um die Nachricht anzuzeigen

Dies stört Ihren Funktionscode und führt zu seltsamen Randfällen. Wenn Sie Ihre Nachricht perfekt zentrieren möchten, erhöht dies die Komplexität.

Rollen Sie Ihren eigenen Table View Controller

Sie verlieren integrierte Funktionen wie refreshControl und erfinden das Rad neu. Halten Sie sich an UITableViewController, um die bestmöglichen Ergebnisse zu erzielen.

Hinzufügen von UITableViewController als untergeordneten Ansichtscontroller

Ich habe das Gefühl, dass Sie in iOS 7+ Probleme mit contentInset haben werden - und warum die Dinge komplizieren?

Meine Lösung

Die beste Lösung, die ich mir ausgedacht habe (und die natürlich nicht ideal ist), besteht darin, eine spezielle Ansicht zu erstellen, die auf einer Bildlaufansicht sitzen und entsprechend handeln kann. In iOS 7 wird dies mit contentInset-Wahnsinn offensichtlich kompliziert, aber es ist machbar.

Dinge, auf die Sie achten müssen:

  • Tabellentrennzeichen werden irgendwann während reloadData nach vorne gebracht - Sie müssen sich davor schützen
  • contentInset / contentOffset - Beobachten Sie diese Schlüssel in Ihrer speziellen Ansicht
  • Tastatur - Wenn Sie nicht möchten, dass die Tastatur im Weg ist, ist dies eine weitere Berechnung
  • Autolayout - Sie können sich nicht auf Rahmenänderungen verlassen, um Ihre Ansicht zu positionieren

Sobald Sie dies einmal in einer UIView-Unterklasse herausgefunden haben, können Sie es für alles verwenden - Laden von Spinnern, Deaktivieren von Ansichten, Anzeigen von Fehlermeldungen usw.

xtravar
quelle
Können Sie Ihre Antwort näher erläutern? Woran erkennt man, ob die Tabelle leer ist? Um dann "entsprechend zu handeln".
Michael Ozeryansky
Sie wissen, dass Ihre Tabelle leer ist, weil Sie diejenige sind, die Ihre Tabelle bevölkert. In Ihrem View Controller haben Sie also einen Rückruf zum asynchronen Laden. Wenn in diesem Rückruf if (itemsToShow.count == 0) {Ihre Ansicht zur Bildlaufansicht hinzufügen}. Der schwierige Teil besteht darin, diese Draufsicht ('Schild- / Nachrichtenansicht') so zu positionieren, dass sie den gesamten Rahmen der Bildlaufansicht abzüglich contentInset usw. einnimmt, sodass die Nachricht vertikal zentriert ist.
Xtraravar
Wie fügt man eine Ansicht über der Tabellenansicht hinzu? self.view ist die Tabellenansicht und wenn ich sie verwende, ist addSubViewsie an die Tabellenansicht angehängt, was immer Probleme mit dem automatischen Layout verursacht.
Testen
Die Ansicht, die Sie in der Tabellenansicht platzieren, sollte kein Autolayout verwenden, und die Tabellenansicht selbst verwendet kein Autolayout.
Xtraravar
1
Sie haben dort einen Ansatz verpasst. Sie können einen UITableViewController verwenden und ihn einem untergeordneten
UIViewController
3

Dies ist die beste und einfachste Lösung.

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)];
label.text = @"This list is empty";
label.center = self.view.center;
label.textAlignment = NSTextAlignmentCenter;
[view addSubview:label];

self.tableView.backgroundView = view;
Rajesh Maurya
quelle
2

Nachricht für leere Liste anzeigen, ob UITableView oder UICollectionView .

extension UIScrollView {
    func showEmptyListMessage(_ message:String) {
        let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: self.bounds.size.width, height: self.bounds.size.height))
        let messageLabel = UILabel(frame: rect)
        messageLabel.text = message
        messageLabel.textColor = .black
        messageLabel.numberOfLines = 0
        messageLabel.textAlignment = .center
        messageLabel.font = UIFont.systemFont(ofSize: 15)
        messageLabel.sizeToFit()

        if let `self` = self as? UITableView {
            self.backgroundView = messageLabel
            self.separatorStyle = .none
        } else if let `self` = self as? UICollectionView {
            self.backgroundView = messageLabel
        }
    }
}

Verwendung:

if cellsViewModels.count == 0 {
    self.tableView.showEmptyListMessage("No Product In List!")
}

ODER:

if cellsViewModels.count == 0 {
    self.collectionView?.showEmptyListMessage("No Product In List!")
}

Denken Sie daran: Vergessen Sie nicht, das Nachrichtenetikett zu entfernen, falls die Daten nach der Aktualisierung eingehen.

Gurjit Singh
quelle
1
Ich würde eine if-Bedingung hinzufügen, wenn messages.count! = 0 {show}
Eddwin Paz
1

Wählen Sie Ihre tableviewController-Szene im Storyboard aus

Geben Sie hier die Bildbeschreibung ein

Drag & Drop UIView Beschriftung mit Ihrer Nachricht hinzufügen (z. B. Keine Daten)

Geben Sie hier die Bildbeschreibung ein

Erstellen Sie einen UIView-Ausgang (z. B. für yournoDataView) auf Ihrem TableViewController.

und in viewDidLoad

self.tableView.backgroundView = yourNoDataView

gaurav bhardwaj
quelle
1

Verwenden von Swift 4.2

  func numberOfSections(in tableView: UITableView) -> Int
{
    var numOfSections: Int = 0
    if self.medArray.count > 0
    {
        tableView.separatorStyle = .singleLine
        numOfSections            = 1
        tableView.backgroundView = nil
    }
    else
    {
        let noDataLabel: UILabel  = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
        noDataLabel.text          = "No  Medicine available.Press + to add New Pills "
        noDataLabel.textColor     = UIColor.black
        noDataLabel.textAlignment = .center
        tableView.backgroundView  = noDataLabel
        tableView.separatorStyle  = .none
    }
    return numOfSections
}
M Murteza
quelle
1

Sie können dies Ihrer Basisklasse hinzufügen.

var messageLabel = UILabel()

func showNoDataMessage(msg: String) {
    let rect = CGRect(origin: CGPoint(x: 0, y :self.view.center.y), size: CGSize(width: self.view.bounds.width - 16, height: 50.0))
    messageLabel = UILabel(frame: rect)
    messageLabel.center = self.view.center
    messageLabel.text = msg
    messageLabel.numberOfLines = 0
    messageLabel.textColor = Colors.grayText
    messageLabel.textAlignment = .center;
    messageLabel.font = UIFont(name: "Lato-Regular", size: 17)
    self.view.addSubview(messageLabel)
    self.view.bringSubviewToFront(messageLabel)
}

Zeigen Sie es so in der Klasse, wenn Sie die Daten von der API erhalten.

func populateData(dataSource : [PRNJobDataSource]){
    self.dataSource = dataSource
    self.tblView.reloadData()
    if self.dataSource.count == 0 {self.showNoDataMessage(msg: "No data found.")}
}

Verstecke es so.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if self.dataSource.count > 0 {self.hideNoDataMessage()}
    return dataSource.count
}

func hideNoDataMessage(){
    messageLabel.removeFromSuperview()
}
Mudassir Asghar
quelle
Hey @ Mudassir-Asghar, wie sieht die Funktion hideNoDataMessage aus?
Saamer
1
Hallo, @Saamer, ich habe gerade die Antwort oben aktualisiert.
Vielen
0

Schnelle Version, aber bessere und einfachere Form. ** 3.0

Ich hoffe es dient Ihrem Zweck ......

In Ihrem UITableViewController.

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if searchController.isActive && searchController.searchBar.text != "" {
        if filteredContacts.count > 0 {
            self.tableView.backgroundView = .none;
            return filteredContacts.count
        } else {
            Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self)
            return 0
        }
    } else {
        if contacts.count > 0 {
            self.tableView.backgroundView = .none;
            return contacts.count
        } else {
            Helper.EmptyMessage(message: ConstantMap.NO_CONTACT_FOUND, viewController: self)
            return 0
        }
    }
}

Helferklasse mit Funktion:

 /* Description: This function generate alert dialog for empty message by passing message and
           associated viewcontroller for that function
           - Parameters:
            - message: message that require for  empty alert message
            - viewController: selected viewcontroller at that time
         */
        static func EmptyMessage(message:String, viewController:UITableViewController) {
            let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: viewController.view.bounds.size.width, height: viewController.view.bounds.size.height))
            messageLabel.text = message
            let bubbleColor = UIColor(red: CGFloat(57)/255, green: CGFloat(81)/255, blue: CGFloat(104)/255, alpha :1)

            messageLabel.textColor = bubbleColor
            messageLabel.numberOfLines = 0;
            messageLabel.textAlignment = .center;
            messageLabel.font = UIFont(name: "TrebuchetMS", size: 18)
            messageLabel.sizeToFit()

            viewController.tableView.backgroundView = messageLabel;
            viewController.tableView.separatorStyle = .none;
        }
Ravindra Shekhawat
quelle
0

Wahrscheinlich nicht die beste Lösung, aber ich habe dies getan, indem ich einfach eine Beschriftung am Ende meiner Tabelle eingefügt habe und wenn die Zeilen = 0 sind, habe ich ihr Text zugewiesen. Ziemlich einfach und erreicht das, was Sie versuchen, mit ein paar Codezeilen.

Ich habe zwei Abschnitte in meiner Tabelle (Jobs und Schulen)

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if (jobs.count == 0 && schools.count == 0) {
        emptyLbl.text = "No jobs or schools"
    } else {
        emptyLbl.text = ""
    }
Zach
quelle
Sie können das Etikett auch durch eine leere Bildansicht ersetzen, wenn count = 0 ist, wenn Sie möchten.
Zach
0

Der einfachste und schnellste Weg, dies zu tun, besteht darin, eine Beschriftung auf das Seitenfenster unter tableView zu ziehen. Erstellen Sie eine Steckdose für das Label und die tableView und fügen Sie eine if-Anweisung hinzu, um das Label und die Tabelle nach Bedarf auszublenden und anzuzeigen. Alternativ können Sie tableView.tableFooterView = UIView (frame: CGRect.zero) zu viewDidLoad () hinzufügen, um einer leeren Tabelle die Wahrnehmung zu geben, dass sie ausgeblendet ist, wenn die Tabellen- und Hintergrundansicht dieselbe Farbe haben.

Yoamod
quelle
(Dieser Beitrag scheint keine qualitativ hochwertige Antwort auf die Frage zu bieten . Bitte bearbeiten Sie Ihre Antwort und vervollständigen Sie sie mit detaillierteren Informationen oder veröffentlichen Sie sie einfach als Kommentar zur Frage.)
sɐunıɔ ןɐ qɐp
0

Ich habe einige Änderungen vorgenommen, damit wir die Anzahl nicht manuell überprüfen müssen. Außerdem habe ich Einschränkungen für das Etikett hinzugefügt, damit nichts schief geht, egal wie groß die Nachricht ist (siehe unten):

extension UITableView {

    fileprivate func configureLabelLayout(_ messageLabel: UILabel) {
        messageLabel.translatesAutoresizingMaskIntoConstraints = false
        let labelTop: CGFloat = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 25:15)
        messageLabel.topAnchor.constraint(equalTo: backgroundView?.topAnchor ?? NSLayoutAnchor(), constant: labelTop).isActive = true
        messageLabel.widthAnchor.constraint(equalTo: backgroundView?.widthAnchor ?? NSLayoutAnchor(), constant: -20).isActive = true
        messageLabel.centerXAnchor.constraint(equalTo: backgroundView?.centerXAnchor ?? NSLayoutAnchor(), constant: 0).isActive = true
    }

    fileprivate func configureLabel(_ message: String) {
        let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height))
        messageLabel.textColor = .black
        messageLabel.numberOfLines = 0
        messageLabel.textAlignment = .center
        let fontSize = CGFloat(UIDevice.current.userInterfaceIdiom == .pad ? 25:15)
        let font: UIFont = UIFont(name: "MyriadPro-Regular", size: fontSize) ?? UIFont()
        messageLabel.font = font
        messageLabel.text = message
        self.backgroundView = UIView()
        self.backgroundView?.addSubview(messageLabel)
        configureLabelLayout(messageLabel)
        self.separatorStyle = .none
    }

    func setEmptyMessage(_ message: String, _ isEmpty: Bool) {
        if isEmpty { // instead of making the check in every TableView DataSource in the project
            configureLabel(message)
        }
        else {
            restore()
        }

    }

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

Verwendung

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let message: String = "The list is empty."
        ticketsTableView.setEmptyMessage(message, tickets.isEmpty)
        return self.tickets.count
    }
Alsh Compiler
quelle
0

Alternativ können Sie eine leicht anpassbare, leichte Bibliothek verwenden

SwiftEmptyState

Enes Karaosman
quelle