Gestire un UITableView vuoto. Stampa un messaggio amichevole


124

Ho un UITableView che in alcuni casi è legale essere vuoto. Quindi, invece di mostrare l'immagine di sfondo dell'app, preferirei stampare un messaggio amichevole sullo schermo, come ad esempio:

Questo elenco è ora vuoto

Qual è il modo più semplice per farlo?


10
Dai

@oleynikd Grazie !!!!!
Luda

Risposte:


173

La proprietà backgroundView di UITableView è tua amica.

In viewDidLoado ovunque reloadDatadovreste determinare se la vostra tabella è vuota o meno e aggiornare la proprietà backgroundView di UITableView con una UIView contenente un UILabel o semplicemente impostarla su zero. Questo è tutto.

Ovviamente è possibile fare in modo che l'origine dati di UITableView faccia il doppio dovere e restituisca una cella speciale "la lista è vuota", mi sembra un kludge. All'improvviso numberOfRowsInSection:(NSInteger)sectiondeve calcolare il numero di righe di altre sezioni di cui non è stato chiesto per assicurarsi che anche loro siano vuote. Devi anche creare una cella speciale con il messaggio vuoto. Inoltre, non dimenticare che probabilmente devi cambiare l'altezza della tua cella per accogliere il messaggio vuoto. È tutto fattibile ma sembra un cerotto sopra il cerotto.


12
BackgroundView è la soluzione migliore, penso. Grazie!
Ferran Maylinch

1
Uno svantaggio è che se la visualizzazione tabella viene abbassata il messaggio rimane nella sua posizione. Preferirei avere like nell'app store sotto aggiornamenti. Qui il messaggio vuoto va con il comportamento di scorrimento ...
test del

@testing ovviamente se hai bisogno del messaggio vuoto per scorrere non puoi usare la visualizzazione in background in quanto non fa parte della gerarchia di scorrimento. Probabilmente vorrai usare una sezione personalizzata e UITableViewCell per lo stato vuoto.
LightningStryk

Attiva / disattiva backgroundViewproprietà nascoste è la strada da percorrere. Con DZNEmptyDataSet, dobbiamo usare il suoemptyDataSetSource
onmyway133

Se vuoi aggiungere dei pulsanti, devi fare: tableView.backgroundView!.userInteraction = truedopo la riga che hai impostato tableView.backgroundView = constructMyViewWithButtons(), o comunque lo hai impostato.
kbpontius

90

Come la risposta di Jhonston, ma l'ho preferita come estensione:

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

Uso:

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
}

Grazie per il tuo suggerimento.
ssowri1

1
L'estensione è migliore! Grazie.
Ogulcan Orhan

Adoro l'estensione :)
Alix

1
Se si dispone di sezioni, quindi avrete bisogno di spostare questa logica al func numberOfSections(in tableView: UITableView) -> Intmetodo
artigianale

87

Sulla base delle risposte qui, ecco una lezione veloce che ho fatto che puoi usare nel tuo file 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;
    }
}

Nel tuo UITableViewControllerpuoi chiamare questonumberOfSectionsInTableView(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
    }
}

inserisci qui la descrizione dell'immagine

Con un piccolo aiuto da http://www.appcoda.com/pull-to-refresh-uitableview-empty/


vorrei anche aggiungere un'immagine ad esso, però. Ma un'ottima soluzione rapida.
AnBisw

10
usa un'estensione invece di una classe (non passare il controller di visualizzazione)
Cesare

Non sono riuscito a far funzionare il codice sopra, ma sono stato in grado di far funzionare il codice in questa risposta (la prima), nel caso in cui altri avessero lo stesso problema. Inoltre penso che anche la seconda risposta funzionerebbe (usando il dock della scena) - stackoverflow.com/questions/28532926/…
Renee Olson,

viewController.tableView.separatorStyle = .nonenon è richiesto.
Dmitry

17

Consiglio la seguente libreria: DZNEmptyDataSet

Il modo più semplice per aggiungerlo al tuo progetto è usarlo con Cocaopods in questo modo: pod 'DZNEmptyDataSet'

Nel tuo TableViewController aggiungi la seguente istruzione di importazione (Swift):

import DZNEmptyDataSet

Quindi assicurati che la tua classe sia conforme a DNZEmptyDataSetSourcee in questo DZNEmptyDataSetDelegatemodo:

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

Nel tuo viewDidLoadaggiungi le seguenti righe di codice:

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

Ora tutto ciò che devi fare per mostrare lo stato vuoto è:

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

Questi metodi non sono obbligatori, è anche possibile mostrare solo lo stato vuoto senza un pulsante, ecc.

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

Ho problemi con DZEmptyDataSet non allineato verticalmente correttamente. Qualcuno ha avuto lo stesso problema?
amariduran

12

Un modo per farlo sarebbe modificare l'origine dati in modo che ritorni 1quando il numero di righe è zero e produrre una cella speciale (magari con un identificatore di cella diverso) nel tableView:cellForRowAtIndexPath:metodo.

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

Questo può diventare un po 'complicato se hai più controller di visualizzazione tabella che devi mantenere, perché qualcuno alla fine dimenticherà di inserire un segno di zero. Un approccio migliore è creare un'implementazione separata di UITableViewDataSourceun'implementazione che restituisce sempre una singola riga con un messaggio configurabile (chiamiamolo EmptyTableViewDataSource). Quando i dati gestiti dal controller della vista tabella cambiano, il codice che gestisce la modifica verifica se i dati sono vuoti. Se non è vuoto, imposta il controller della vista tabella con la sua origine dati regolare; in caso contrario, impostarlo con un'istanza di EmptyTableViewDataSourceche è stata configurata con il messaggio appropriato.


5
Ho avuto problemi a farlo con le tabelle in cui sono state eliminate righe deleteRowsAtIndexPaths:withRowAnimation:poiché il numero restituito da numberOfRowsInSectiondeve corrispondere al risultato di $ numRows - $ rowsDeleted.
Animal451

4
Consiglio vivamente di non farlo. Enigma il tuo codice con casi limite.
xtravar

2
@xtravar Piuttosto che downvoting, considera di pubblicare la tua risposta.
dasblinkenlight

1
Ho seguito quel percorso e questo porta a una serie di problemi. Nella mia esperienza, è quasi sempre meglio aumentare le API di Apple piuttosto che provare a sostituirle.
xtravar

1
Questa soluzione non funzionerà con NSFetchedResultsController. Proverò invece l'approccio backgroundView.
Sam

10

Ho usato il messaggio titleForFooterInSection per questo. Non so se sia subottimale o meno, ma funziona.

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

2
Bel trucco e mi sembra abbastanza pulito. Ecco una battuta:return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
TruMan1

8

Quindi per una soluzione più sicura:

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

e anche per 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
  }
}

Soluzione più generica:

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

7

Posso solo consigliare di trascinare e rilasciare un UITextView all'interno del TableView dopo le celle. Effettuare una connessione al ViewController e nasconderlo / visualizzarlo quando appropriato (ad es. Ogni volta che la tabella viene ricaricata).

inserisci qui la descrizione dell'immagine


Questo è il modo più semplice)!
moonvader

Un tale doloroso mal di testa alla maniera della mela; grazie per questa idea
Eenvincible

5

Usare backgroundView va bene, ma non scorre bene come in Mail.app.

Ho fatto qualcosa di simile a quello che ha fatto xtravar .

Ho aggiunto una visualizzazione al di fuori della gerarchia di visualizzazione di tableViewController. gerarchia

Quindi ho usato il seguente codice in 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

Fondamentalmente ho aggiunto il emptyStateViewcome sottoview tableViewdell'oggetto. Poiché i separatori si sovrappongono alla vista, ho impostato il loro colore su clearColor. Per tornare al colore del separatore predefinito, puoi semplicemente impostarlo su nil.


Funziona abbastanza bene! Ma se hai elementi per pull da aggiornare, ad esempio, questo non scorre con loro. Ho trovato meglio impostare il tableHeaderView, e assicurarmi che si ridimensiona per adattarsi .
Hannele

4

Secondo Apple, l' utilizzo di un controller di visualizzazione del contenitore è il modo giusto per farlo .

Ho messo tutte le mie viste di stato vuote in uno Storyboard separato. Ciascuno sotto la propria sottoclasse UIViewController. Aggiungo contenuti direttamente sotto la loro visualizzazione principale. Se è necessaria un'azione / pulsante, ora hai già un controller per gestirlo.
Quindi è solo una questione di istanziare il controller di visualizzazione desiderato da quello Storyboard, aggiungerlo come controller di visualizzazione figlio e aggiungere la visualizzazione del contenitore alla gerarchia di tableView (vista secondaria). Anche la visualizzazione dello stato vuoto sarà scorrevole, il che è piacevole e ti consente di implementare il pull per aggiornare.

Leggere il capitolo "Aggiunta di un controller di visualizzazione figlio al contenuto" per informazioni su come implementarlo.

Assicurati solo di impostare il frame della visualizzazione figlio come (0, 0, tableView.frame.width, tableView.frame.height) e le cose saranno centrate e allineate correttamente.


3

In primo luogo, i problemi con altri approcci popolari.

BackgroundView

La visualizzazione in background non si centra bene se si utilizza il semplice caso di impostarla come UILabel.

Celle, intestazioni o piè di pagina per visualizzare il messaggio

Ciò interferisce con il codice funzionale e introduce strani casi limite. Se vuoi centrare perfettamente il tuo messaggio, questo aggiunge un altro livello di complessità.

Rotolamento del controller della visualizzazione della tabella

Perdi la funzionalità integrata, come refreshControl, e reinventa la ruota. Attenersi a UITableViewController per i migliori risultati mantenibili.

Aggiunta di UITableViewController come controller di visualizzazione figlio

Ho la sensazione che ti ritroverai con problemi di ContentInset in iOS 7+, inoltre perché complicare le cose?

La mia soluzione

La soluzione migliore che ho trovato (e, certo, questo non è l'ideale) è creare una vista speciale che possa essere posizionata sopra una vista a scorrimento e agire di conseguenza. Questo ovviamente diventa complicato in iOS 7 con la follia di contentInset, ma è fattibile.

Cose a cui devi prestare attenzione:

  • i separatori di tabella vengono portati in primo piano a un certo punto durante reloadData: devi stare attento a questo
  • contentInset / contentOffset: osserva quei tasti nella tua vista speciale
  • tastiera: se non vuoi che la tastiera si intrometta, questo è un altro calcolo
  • autolayout: non puoi dipendere dalle modifiche del frame per posizionare la visualizzazione

Dopo averlo capito una volta in una sottoclasse UIView, puoi usarlo per tutto: caricamento di spinner, disabilitazione delle visualizzazioni, visualizzazione di messaggi di errore, ecc.


Puoi approfondire la tua risposta. Come fai a sapere se la tabella è vuota? Per poi "agire di conseguenza".
Michael Ozeryansky

Sai che il tuo tavolo è vuoto perché sei tu a popolare il tuo tavolo. Quindi, nel tuo controller di visualizzazione, avresti un callback di caricamento asincrono. In quella richiamata, if (itemsToShow.count == 0) {add your view to the scroll view}. La parte complicata è rendere quella vista dall'alto ('vista scudo / messaggio') posizionata in modo da occupare l'intero fotogramma della vista a scorrimento, meno contentInset, ecc., In modo che il messaggio sia centrato verticalmente.
xtravar

Come si aggiunge una vista sopra la vista tabella? self.view è la vista tabella e, se la uso addSubView, è collegata alla vista tabella, il che crea sempre problemi con il layout automatico.
test

La vista che inserisci nella vista tabella non deve utilizzare il layout automatico e la vista tabella stessa non utilizza il layout automatico.
xtravar

1
Hai perso un approccio lì; È possibile utilizzare un UITableViewController e aggiungerlo come controller di visualizzazione figlio a un normale UIViewController
user1169629

3

Questa è la soluzione migliore e semplice.

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;

2

Mostra messaggio per l'elenco vuoto, sia che sia UITableView o 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
        }
    }
}

usi:

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

O:

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

Ricorda: non dimenticare di rimuovere l'etichetta del messaggio nel caso in cui i dati arrivino dopo l'aggiornamento.


1
Aggiungerei una condizione if se messages.count! = 0 {show}
Eddwin Paz

1

Seleziona la tua scena tableviewController nello storyboard

inserisci qui la descrizione dell'immagine

Trascina e rilascia UIView Aggiungi etichetta con il tuo messaggio (es: Nessun dato)

inserisci qui la descrizione dell'immagine

creare una presa di UIView (ad esempio, yournoDataView) sul tuo TableViewController.

e in viewDidLoad

self.tableView.backgroundView = yourNoDataView


1

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

1

Puoi aggiungerlo alla tua classe Base.

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

Mostralo in questo modo nella classe su come ottenere i dati da api.

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

Nascondilo in questo modo.

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

func hideNoDataMessage(){
    messageLabel.removeFromSuperview()
}

Hey @ Mudassir-Asghar com'è la funzione hideNoDataMessage?
Saamer

1
Ciao, @ Saamer ho appena aggiornato la risposta sopra. grazie per averlo fatto notare, spero che questo aiuti :)
Mudassir Asghar

0

Versione rapida ma forma migliore e più semplice. ** 3.0

Spero che serva il tuo scopo ...

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

Classe helper con funzione:

 /* 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;
        }

0

Probabilmente non è la soluzione migliore, ma l'ho fatto semplicemente mettendo un'etichetta nella parte inferiore della mia tabella e se le righe = 0 gli assegno del testo. Abbastanza facile e ottiene ciò che stai cercando di fare con poche righe di codice.

Ho due sezioni nella mia tabella (lavori e scuole)

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

    if (jobs.count == 0 && schools.count == 0) {
        emptyLbl.text = "No jobs or schools"
    } else {
        emptyLbl.text = ""
    }

Potresti anche sostituire l'etichetta con una visualizzazione immagine vuota quando count = 0, se lo desideri ..
Zach

0

Il modo più semplice e veloce per farlo è trascinare un'etichetta sul pannello laterale sotto tableView. Creare una presa per l'etichetta e la tableView e aggiungere un'istruzione if per nascondere e mostrare l'etichetta e la tabella secondo necessità. In alternativa puoi aggiungere tableView.tableFooterView = UIView (frame: CGRect.zero) a viewDidLoad () per dare a una tabella vuota la percezione che sia nascosta se la tabella e la vista di sfondo hanno lo stesso colore.


(Questo post non sembra fornire una risposta di qualità alla domanda. Modifica la risposta e completala con informazioni più dettagliate, oppure pubblicala come commento alla domanda).
sɐunıɔ ןɐ qɐp

0

Ho apportato alcune modifiche in modo che non sia necessario controllare manualmente il conteggio, inoltre ho aggiunto vincoli per l'etichetta in modo che nulla vada storto, non importa quanto sia grande il messaggio come mostrato di seguito:

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

uso

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.