Manipulando um UITableView vazio. Imprimir uma mensagem amigável


124

Eu tenho um UITableView que, em alguns casos, é legal estar vazio. Portanto, em vez de mostrar a imagem de plano de fundo do aplicativo, prefiro imprimir uma mensagem amigável na tela, como:

Esta lista está agora vazia

Qual é a maneira mais simples de fazer isso?


10

@oleynikd Thank you !!!!!
Luda

Respostas:


173

A propriedade backgroundView do UITableView é sua amiga.

Em viewDidLoadou em qualquer lugar que você reloadDatadeve determinar se a sua tabela está vazia ou não e atualize a propriedade backgroundView do UITableView com uma UIView contendo um UILabel ou apenas defina-a como nula. É isso aí.

É claro que é possível fazer com que a fonte de dados do UITableView cumpra duas funções e retorne uma célula especial "list is empty", isso me parece uma ilusão. De repente, numberOfRowsInSection:(NSInteger)sectioné preciso calcular o número de linhas de outras seções que não foram solicitadas para garantir que elas também estejam vazias. Você também precisa criar uma célula especial que tenha a mensagem vazia. Além disso, não esqueça que você provavelmente precisará alterar a altura do seu celular para acomodar a mensagem vazia. Tudo isso é possível, mas parece um band-aid em cima do band-aid.


12
O backgroundView é a melhor solução, eu acho. Obrigado!
Ferran Maylinch

1
Uma desvantagem é que, se a exibição da tabela for puxada para baixo, a mensagem permanecerá em sua posição. Eu gostaria de ter como no aplicativo da loja de aplicativos em atualizações. Aqui a mensagem vazia acompanha o comportamento da rolagem ...
testando

@ testing, obviamente, se você precisar de mensagens vazias para rolar, não poderá usar a exibição em segundo plano, pois isso não faz parte da hierarquia de rolagem. Você provavelmente deseja usar uma seção personalizada e UITableViewCell para o estado vazio.
LightningStryk

Alternar backgroundViewpropriedade oculta é o caminho a percorrer. Com DZNEmptyDataSet, temos que usar o seuemptyDataSetSource
onmyway133 /

Se você deseja adicionar botões, deve fazer: tableView.backgroundView!.userInteraction = trueapós a linha que você definiu tableView.backgroundView = constructMyViewWithButtons(), ou como você o definiu.
Kbpontius #

90

O mesmo que a resposta de Jhonston, mas eu a preferi como uma extensão:

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
}

Obrigado pela sua sugestão.
precisa saber é o seguinte

1
Extensão é melhor! Obrigado.
Ogulcan Orhan

Amo a extensão :)
Alix

1
Se você tiver seções, precisará mover essa lógica para o func numberOfSections(in tableView: UITableView) -> Intmétodo
crie

87

Com base nas respostas aqui, aqui está uma aula rápida que eu fiz que você pode usar no seu 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;
    }
}

No seu UITableViewControllervocê pode chamar isso emnumberOfSectionsInTableView(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
    }
}

insira a descrição da imagem aqui

Com uma pequena ajuda de http://www.appcoda.com/pull-to-refresh-uitableview-empty/


também gostaria de adicionar uma imagem a ele. Mas uma ótima solução rápida.
AnBisw

10
usar uma extensão em vez de uma classe (não passar no controlador de vista)
Cesare

Não consegui que o código acima funcionasse para mim, mas consegui que o código nesta resposta (primeira) funcionasse, caso outras pessoas tivessem o mesmo problema. Também acho que o 2º resposta iria funcionar tão bem (usando o cais cena) - stackoverflow.com/questions/28532926/...
Renee Olson

viewController.tableView.separatorStyle = .nonenão é obrigatório.
Dmitry

17

Eu recomendo a seguinte biblioteca: DZNEmptyDataSet

A maneira mais fácil de adicioná-lo ao seu projeto é usá-lo com Cocaopods assim: pod 'DZNEmptyDataSet'

No seu TableViewController, adicione a seguinte declaração de importação (Swift):

import DZNEmptyDataSet

Em seguida, certifique-se de seus conforma classe para o DNZEmptyDataSetSourcee DZNEmptyDataSetDelegateassim:

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

No seu, viewDidLoadadicione as seguintes linhas de código:

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

Agora tudo o que você precisa fazer para mostrar o estado vazio é:

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

Esses métodos não são obrigatórios, também é possível apenas mostrar o estado vazio sem um botão etc.

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

Estou tendo problemas com o DZEmptyDataSet não sendo alinhado verticalmente corretamente. Alguém já teve esse mesmo problema?
amariduran 27/09/18

12

Uma maneira de fazer isso seria modificar sua fonte de dados para retornar 1quando o número de linhas for zero e produzir uma célula de finalidade especial (talvez com um identificador de célula diferente) no tableView:cellForRowAtIndexPath:método.

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

Isso pode ficar um pouco complicado se você tiver vários controladores de exibição de tabela que precisam manter, porque alguém se esquecerá de inserir uma verificação zero. Uma abordagem melhor é criar uma implementação separada de uma UITableViewDataSourceimplementação que sempre retorne uma única linha com uma mensagem configurável (vamos chamá-lo EmptyTableViewDataSource). Quando os dados gerenciados pelo seu controlador de exibição de tabela são alterados, o código que gerencia a alteração verifica se os dados estão vazios. Se não estiver vazio, configure seu controlador de exibição de tabela com sua fonte de dados regular; caso contrário, configure-o com uma instância do EmptyTableViewDataSourceque foi configurada com a mensagem apropriada.


5
Eu tive problemas ao fazer isso com tabelas com linhas excluídas, deleteRowsAtIndexPaths:withRowAnimation:pois o número retornado das numberOfRowsInSectionnecessidades corresponde ao resultado de $ numRows - $ linesDeleted.
precisa saber é o seguinte

4
Eu recomendo muito, altamente contra isso. Cria seu código com casos extremos.
Xtravar

2
@xtravar Em vez de reduzir a votação, considere postar sua própria resposta.
dasblinkenlight

1
Eu segui esse caminho e leva a sua própria variedade de problemas. Na minha experiência, quase sempre é melhor aumentar as APIs da Apple do que tentar substituí-las.
Xtravar

1
Esta solução não funcionará com NSFetchedResultsController. Vou tentar a abordagem backgroundView.
6134 Sam

10

Eu tenho usado a mensagem titleForFooterInSection para isso. Não sei se isso é subótimo ou não, mas funciona.

-(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
Bom truque e parece bastante limpo para mim. Aqui está uma lista:return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
TruMan1 /

8

Portanto, para uma solução mais segura:

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 UICollectionViewtambém:

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

Solução mais genérica:

    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

Só posso recomendar arrastar e soltar um UITextView dentro do TableView após as células. Faça uma conexão com o ViewController e oculte / exiba quando apropriado (por exemplo, sempre que a tabela for recarregada).

insira a descrição da imagem aqui


Essa é a maneira mais fácil)!
Moonvader 5/05

Uma dor de cabeça tão dolorosa à maneira da maçã; obrigado por essa idéia
Eenvincible

5

Usar o backgroundView é bom, mas não rola muito bem como no Mail.app.

Eu fiz algo semelhante ao que o xtravar fez.

Eu adicionei uma visualização fora da hierarquia da tableViewController. hierarquia

Então eu usei o seguinte código em 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

Basicamente, eu adicionei o emptyStateViewcomo uma subview do tableViewobjeto. Como os separadores se sobrepõem à vista, defino sua cor como clearColor. Para voltar à cor padrão do separador, basta configurá-lo como nil.


Isso funciona muito bem! Mas se você tem elementos para puxar para atualizar, por exemplo, isso não rola com eles. Achei melhor definir tableHeaderViewe redimensionar para caber .
Hannele

4

Usar um Container View Controller é a maneira correta de fazê-lo, de acordo com a Apple .

Coloquei todas as minhas visualizações de estado vazias em um Storyboard separado. Cada um abaixo da sua própria subclasse UIViewController. Eu adiciono conteúdo diretamente na visualização raiz. Se qualquer ação / botão for necessária, agora você já possui um controlador para lidar com isso.
Depois, basta instanciar o controlador de exibição desejado a partir desse Storyboard, adicione-o como um controlador de exibição filho e adicione a exibição de contêiner à hierarquia do tableView (sub-exibição). Sua exibição de estado vazio também pode ser rolada, o que é bom e permite que você implemente pull to refresh.

Leia o capítulo 'Adicionando um controlador de exibição infantil ao seu conteúdo' para obter ajuda sobre como implementar.

Apenas certifique-se de definir o quadro de exibição filho como (0, 0, tableView.frame.width, tableView.frame.height)e as coisas serão centralizadas e alinhadas corretamente.


3

Primeiro, os problemas com outras abordagens populares.

BackgroundView

A exibição de plano de fundo não é muito boa se você usar o simples caso de defini-la como um UILabel.

Células, cabeçalhos ou rodapés para exibir a mensagem

Isso interfere no seu código funcional e apresenta casos extremos estranhos. Se você deseja centralizar perfeitamente sua mensagem, isso adiciona outro nível de complexidade.

Rolando seu próprio controlador de exibição de tabela

Você perde a funcionalidade interna, como refreshControl, e reinventa a roda. Atenha-se ao UITableViewController para obter os melhores resultados de manutenção.

Adicionando UITableViewController como um controlador de exibição filho

Tenho a sensação de que você terminará com os problemas contentInset no iOS 7+ - além de por que complicar as coisas?

Minha solução

A melhor solução que eu encontrei (e, concedido, isso não é o ideal) é criar uma visualização especial que possa ficar no topo de uma visualização de rolagem e agir de acordo. Obviamente, isso fica complicado no iOS 7 com a loucura contentInset, mas é factível.

Itens a serem observados:

  • separadores de tabela são trazidos para a frente em algum momento durante o reloadData - você precisa se proteger contra isso
  • contentInset / contentOffset - observe essas chaves em sua exibição especial
  • teclado - se você não quer que o teclado atrapalhe, esse é outro cálculo
  • autolayout - você não pode depender de alterações de quadro para posicionar sua visualização

Depois de descobrir isso uma vez em uma subclasse do UIView, você pode usá-lo para tudo - carregar spinners, desativar visualizações, mostrar mensagens de erro etc.


Você pode elaborar sua resposta. Como você sabe se a mesa está vazia? Para então "agir em conformidade".
Michael Ozeryansky

Você sabe que sua mesa está vazia porque é você quem está preenchendo sua mesa. Portanto, no seu controlador de exibição, você teria um retorno de chamada de carregamento assíncrono. Nesse retorno de chamada, se (itemsToShow.count == 0) {adicione sua visualização à visualização de rolagem}. A parte complicada é fazer com que a exibição superior ('exibição de escudo / mensagem') seja posicionada para ocupar todo o quadro da exibição de rolagem, menos contentInset etc., para que a mensagem seja centralizada verticalmente.
Xtravar

Como você adiciona uma exibição na parte superior da tabela? self.view é a visualização da tabela e, se eu a usar addSubView, é anexada à visualização da tabela, o que sempre causa problemas no layout automático.
testando

A exibição que você coloca na exibição da tabela não deve usar o autolayout e a tableview em si não usa o autolayout.
Xtravar

1
Você perdeu uma abordagem lá; Você poderia usar um UITableViewController e adicioná-lo como um controlador de vista criança a um UIViewController regulares
user1169629

3

Esta é a melhor e mais simples solução.

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

Mostrar mensagem para lista vazia, seja seu UITableView ou 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
        }
    }
}

Usos:

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

OU:

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

Lembre-se: Não esqueça de remover o rótulo da mensagem, caso os dados cheguem após a atualização.


1
Eu gostaria de acrescentar uma condição if se messages.count = 0 {Mostrar}!
Eddwin Paz

1

Cena do controlador no storyboard

insira a descrição da imagem aqui

Arraste e solte UIView Adicione um marcador com sua mensagem (por exemplo: Sem dados)

insira a descrição da imagem aqui

crie uma saída do UIView (por exemplo, yournoDataView) no seu TableViewController.

e em viewDidLoad

self.tableView.backgroundView = yourNoDataView


1

Usando o 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

Você pode adicionar isso à sua 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)
}

Mostre dessa forma na classe sobre como obter os dados da API.

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

Esconda assim.

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, como é a função hideNoDataMessage?
Saamer 16/04

1
Olá, @Saamer, acabei de atualizar a resposta acima. obrigado por apontar, espero que isso ajude :)
Mudassir Asghar

0

Versão rápida, mas melhor e mais simples. ** 3,0

Espero que servidor seu propósito ......

No seu 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 auxiliar com função:

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

Provavelmente não é a melhor solução, mas fiz isso colocando um rótulo na parte inferior da minha tabela e, se as linhas = 0, atribuo-lhe algum texto. Muito fácil e consegue o que você está tentando fazer com algumas linhas de código.

Tenho duas seções na minha mesa (empregos e escolas)

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

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

Você também pode substituir o rótulo com um ImageView vazio quando count = 0 se você queria ..
Zach

0

A maneira mais fácil e rápida de fazer isso é arrastar um rótulo para o painel lateral sob tableView. Crie uma saída para o rótulo e o tableView e adicione uma instrução if para ocultar e mostrar o rótulo e a tabela conforme necessário. Como alternativa, você pode adicionar tableView.tableFooterView = UIView (frame: CGRect.zero) a isto viewDidLoad () para dar a uma tabela vazia a percepção de que ela está oculta se a tabela e a exibição em segundo plano tiverem a mesma cor.


(Esta postagem parece não fornecer uma resposta de qualidade à pergunta. Edite sua resposta e complete-a com informações mais detalhadas ou apenas publique-a como um comentário à pergunta).
sɐunıɔ ןɐ qɐp

0

Fiz algumas alterações para não precisarmos verificar a contagem manualmente, também adicionei restrições para o rótulo para que nada dê errado, não importa o tamanho da mensagem, como mostrado abaixo:

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
    }

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.