Обработка пустого UITableView. Распечатать дружеское сообщение


124

У меня есть UITableView, который в некоторых случаях может быть пустым. Поэтому вместо отображения фонового изображения приложения я бы предпочел напечатать на экране дружественное сообщение, например:

Этот список сейчас пуст

Как это сделать проще всего?


10
Посмотрите этот проект: github.com/dzenbot/DZNEmptyDataSet
oleynikd

@oleynikd Спасибо !!!!!
Люда

Ответы:


173

Свойство backgroundView UITableView - ваш друг.

В viewDidLoadили в любом reloadDataдругом месте, где вы должны определить, является ли ваша таблица пустой или нет, и обновить свойство backgroundView UITableView с помощью UIView, содержащего UILabel, или просто установить его в nil. Вот и все.

Конечно, можно заставить источник данных UITableView выполнять двойную функцию и возвращать специальную ячейку «список пуст», это кажется мне кладжем. Внезапно numberOfRowsInSection:(NSInteger)sectionприходится вычислять количество строк других разделов, о которых не спрашивали, чтобы убедиться, что они тоже пусты. Также нужно сделать специальную ячейку с пустым сообщением. Также не забывайте, что вам, вероятно, нужно изменить высоту вашей ячейки, чтобы разместить пустое сообщение. Все это выполнимо, но похоже на пластырь поверх пластыря.


12
Я думаю, что backgroundView - лучшее решение. Спасибо!
Ферран Мэйлинч

1
Одним из недостатков является то, что при опускании табличного представления сообщение остается на своем месте. Хотелось бы иметь лайк в приложении app store под обновлениями. Здесь пустое сообщение связано с поведением прокрутки ...
тестирование

@testing очевидно, что если вам нужен пустой обмен сообщениями для прокрутки, вы не можете использовать фоновое представление, поскольку оно не является частью иерархии прокрутки. Вероятно, вы захотите использовать настраиваемый раздел и UITableViewCell для пустого состояния.
LightningStryk

Переключить backgroundViewскрытое свойство - это лучший способ. С DZNEmptyDataSet, мы должны использовать егоemptyDataSetSource
onmyway133

Если вы хотите добавить кнопки, вы должны сделать: tableView.backgroundView!.userInteraction = trueпосле строки, в которой вы установили tableView.backgroundView = constructMyViewWithButtons(), или как вы ее установили.
kbpontius 01

90

То же, что и ответ Jhonston, но я предпочел его как расширение:

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

Использование:

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
}

Спасибо за ваше предложение.
ssowri1

1
Расширение лучше! Спасибо.
Ogulcan Orhan


1
Если у вас есть разделы, то вам нужно переместить эту логику в func numberOfSections(in tableView: UITableView) -> Intметод
ремеслу

87

Основываясь на ответах здесь, я подготовил небольшой урок, который вы можете использовать в своем 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;
    }
}

В вашем UITableViewControllerвы можете позвонить вnumberOfSectionsInTableView(tableView: UITableView) -> Int

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

введите описание изображения здесь

С небольшой помощью http://www.appcoda.com/pull-to-refresh-uitableview-empty/


также хотел бы добавить к нему изображение. Но отличное быстрое решение.
AnBisw

10
используйте расширение вместо класса (не передавайте контроллер представления)
Чезаре

Мне не удалось заставить приведенный выше код работать для меня, но я смог заставить код в этом ответе (первый) работать, на случай, если у других будет такая же проблема. Также я думаю, что второй ответ тоже будет работать (с использованием док-станции сцены) - stackoverflow.com/questions/28532926/…
Рене Олсон

viewController.tableView.separatorStyle = .noneне требуется.
Дмитрий

17

Я рекомендую следующую библиотеку: DZNEmptyDataSet

Самый простой способ добавить его в свой проект - использовать его с Cocaopods следующим образом: pod 'DZNEmptyDataSet'

В свой TableViewController добавьте следующий оператор импорта (Swift):

import DZNEmptyDataSet

Затем убедитесь, что ваш класс соответствует DNZEmptyDataSetSourceи DZNEmptyDataSetDelegateвот так:

class MyTableViewController: UITableViewController, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate

В ваших viewDidLoadдобавьте следующие строки кода:

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

Теперь все, что вам нужно сделать, чтобы показать пустое состояние:

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

Эти методы не являются обязательными, также можно просто показать пустое состояние без кнопки и т. Д.

Для 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)
}

У меня проблемы с DZEmptyDataSet, неправильно выровненным по вертикали. У кого-нибудь была такая же проблема?
amariduran

12

Один из способов сделать это - изменить источник данных, чтобы он возвращался, 1когда количество строк равно нулю, и создавал ячейку специального назначения (возможно, с другим идентификатором ячейки) в tableView:cellForRowAtIndexPath:методе.

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

Это может быть несколько сложнее, если у вас есть несколько контроллеров табличного представления, которые вам нужно поддерживать, потому что кто-то в конечном итоге забудет вставить нулевую проверку. Лучшим подходом является создание отдельной реализации UITableViewDataSourceреализации, которая всегда возвращает одну строку с настраиваемым сообщением (назовем его EmptyTableViewDataSource). Когда данные, которыми управляет ваш контроллер табличного представления, изменяются, код, управляющий изменением, проверяет, пусты ли данные. Если он не пустой, установите в контроллере табличного представления его обычный источник данных; в противном случае установите его с экземпляром EmptyTableViewDataSource, который был настроен с соответствующим сообщением.


5
У меня были проблемы с таблицами, в которых были удалены строки, deleteRowsAtIndexPaths:withRowAnimation:поскольку возвращаемое число numberOfRowsInSectionдолжно соответствовать результату $ numRows - $ rowsDeleted.
Animal451

4
Я очень, очень не рекомендую этого делать. Он загадывает ваш код крайними случаями.
xtravar

2
@xtravar Вместо того, чтобы голосовать против, рассмотрите возможность публикации собственного ответа.
dasblinkenlight

1
Я пошел по этому пути, и он ведет к собственному множеству проблем. По моему опыту, почти всегда лучше дополнять API Apple, чем пытаться их заменить.
xtravar

1
Это решение не будет работать с NSFetchedResultsController. Вместо этого я попробую использовать подход backgroundView.
Сэм

10

Я использовал для этого сообщение titleForFooterInSection. Не знаю, неоптимально это или нет, но работает.

-(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
Хороший трюк и кажется мне довольно чистым. Вот однострочный return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
комментарий

8

Итак, для более безопасного решения:

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

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

Более универсальное решение:

    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

Я могу только рекомендовать перетаскивать UITextView внутри TableView после ячеек. Установите соединение с ViewController и при необходимости скройте / отобразите его (например, при перезагрузке таблицы).

введите описание изображения здесь


Это самый простой способ)!
Moonvader

Такая мучительная головная боль по-яблочной; спасибо за эту идею
Eenvincible

5

Использование backgroundView - это нормально, но не так хорошо, как в Mail.app.

Я сделал что-то похожее на то, что сделал xtravar .

Я добавил представление за пределами иерархии представлений tableViewController. иерархия

Затем я использовал следующий код 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

По сути, я добавил emptyStateViewкак часть tableViewобъекта. Поскольку разделители будут перекрывать вид, я установил для них цвет clearColor. Чтобы вернуться к цвету разделителя по умолчанию, вы можете просто установить его на nil.


Это работает очень хорошо! Но если у вас есть элементы для обновления, например, это не прокручивается вместе с ними. Я обнаружил, что лучше установить tableHeaderViewи убедиться, что размер .
Hannele

4

По мнению Apple, использование Контроллера представления контейнера - правильный способ сделать это .

Я поместил все свои пустые представления состояния в отдельную раскадровку. У каждого есть собственный подкласс UIViewController. Я добавляю контент прямо под их корневое представление. Если требуется какое-либо действие / кнопка, теперь у вас уже есть контроллер для его обработки.
Затем остается лишь создать экземпляр желаемого контроллера представления из этой раскадровки, добавить его в качестве дочернего контроллера представления и добавить представление контейнера в иерархию tableView (подвид). Ваше пустое представление состояния также будет прокручиваемым, что приятно и позволит вам реализовать pull для обновления.

Прочтите главу «Добавление дочернего контроллера представления к вашему контенту», чтобы узнать, как его реализовать.

Просто убедитесь, что вы установили дочернюю рамку просмотра, (0, 0, tableView.frame.width, tableView.frame.height)и все будет правильно отцентрировано и выровнено.


3

Во-первых, проблемы с другими популярными подходами.

BackgroundView

Фоновый вид не будет хорошо центрирован, если вы использовали простой случай установки его как UILabel.

Ячейки, верхние или нижние колонтитулы для отображения сообщения

Это мешает вашему функциональному коду и вызывает странные крайние случаи. Если вы хотите идеально центрировать свое сообщение, это добавляет еще один уровень сложности.

Сворачивание собственного контроллера табличного представления

Вы теряете встроенную функциональность, такую ​​как refreshControl, и заново изобретаете колесо. Придерживайтесь UITableViewController для достижения наилучших поддерживаемых результатов.

Добавление UITableViewController в качестве контроллера дочернего представления

У меня такое чувство, что в iOS 7+ вы столкнетесь с проблемами contentInset - плюс, зачем все усложнять?

Мое решение

Лучшее решение, которое я придумал (и, конечно, не идеально), - это создать специальный вид, который может располагаться поверх прокрутки и действовать соответственно. В iOS 7 это, очевидно, усложняется безумием contentInset, но это выполнимо.

На что следует обратить внимание:

  • разделители таблиц выводятся на передний план в какой-то момент во время reloadData - вам нужно принять меры против этого
  • contentInset / contentOffset - наблюдайте за этими ключами в вашем специальном представлении
  • клавиатура - если вы не хотите, чтобы клавиатура мешала, это еще один расчет
  • autolayout - вы не можете зависеть от изменений кадра, чтобы расположить ваш вид

Как только вы разобрались с этим один раз в одном подклассе UIView, вы можете использовать его для всего - загрузки счетчиков, отключения представлений, отображения сообщений об ошибках и т. Д.


Можете ли вы уточнить в своем ответе. Как узнать, пуст ли стол? Чтобы затем «действовать соответственно».
Михаил Озерянский

Вы знаете, что ваша таблица пуста, потому что вы заполняете ее. Итак, в вашем контроллере представления у вас будет обратный вызов асинхронной загрузки. В этом обратном вызове if (itemsToShow.count == 0) {добавьте свое представление в представление прокрутки}. Сложная часть состоит в том, чтобы расположить этот вид сверху («вид экрана / сообщения») таким образом, чтобы он занимал весь фрейм вида прокрутки, за вычетом contentInset и т. Д., Так что сообщение центрируется по вертикали.
xtravar 03

Как добавить представление поверх представления таблицы? self.view - это табличное представление, и если я использую addSubViewего, прикрепленное к табличному представлению, что всегда создает проблемы с автоматическим макетом.
тестирование

Представление, которое вы размещаете в табличном представлении, не должно использовать автоматическое размещение, а само табличное представление не использует автоматическое размещение.
xtravar 06

1
Вы пропустили там один подход; Вы можете использовать UITableViewController и добавить его как дочерний контроллер представления к обычному UIViewController
user1169629,

3

Это лучшее и простое решение.

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

Показать сообщение для пустого списка, используйте его UITableView или 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
        }
    }
}

Обычаи:

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

ИЛИ:

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

Помните: не забудьте удалить метку сообщения, если данные появятся после обновления.


1
Я бы добавил условие if, если messages.count! = 0 {show}
Эдвин Паз

1

Выберите сцену tableviewController в раскадровке

введите описание изображения здесь

Перетащите метку UIView Add с вашим сообщением (например: Нет данных)

введите описание изображения здесь

создайте выход UIView (скажем, например, yournoDataView) на вашем TableViewController.

и в viewDidLoad

self.tableView.backgroundView = yourNoDataView


1

Использование 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

Вы можете добавить это в свой базовый класс.

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

Покажите это в классе по получению данных из api.

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

Спрячьте это вот так.

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

func hideNoDataMessage(){
    messageLabel.removeFromSuperview()
}

Привет, @ Mudassir-Asghar, как выглядит функция hideNoDataMessage?
Саамер

1
Привет, @Saamer, я только что обновил ответ выше. спасибо, что указали на это, надеюсь, это поможет :)
Мудассир Асгар

0

Быстрая версия, но лучше и проще. ** 3,0

Я надеюсь, что он послужит вашей цели ......

В вашем 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
        }
    }
}

Класс-помощник с функцией:

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

Возможно, не самое лучшее решение, но я сделал это, просто поместив метку внизу моей таблицы, и если row = 0, я назначил ей какой-то текст. Довольно просто, и достигается то, что вы пытаетесь сделать, с помощью нескольких строк кода.

В моей таблице два раздела (вакансии и школы)

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

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

Вы также можете заменить метку пустым изображением при count = 0, если хотите ..
Zach

0

Самый простой и быстрый способ сделать это - перетащить метку на боковую панель под tableView. Создайте выход для метки и tableView и добавьте оператор if, чтобы скрыть и отобразить метку и таблицу по мере необходимости. В качестве альтернативы вы можете добавить tableView.tableFooterView = UIView (frame: CGRect.zero) this для вас viewDidLoad (), чтобы дать пустой таблице ощущение, что она скрыта, если таблица и фоновое представление имеют одинаковый цвет.


(Этот пост не дает качественного ответа на вопрос. Пожалуйста, отредактируйте свой ответ и дополните его более подробной информацией, или просто опубликуйте его как комментарий к вопросу).
sɐunıɔ ןɐ qɐp

0

Я внес несколько изменений, чтобы нам не приходилось проверять счет вручную, а также добавил ограничения для метки, чтобы ничего не случилось, независимо от размера сообщения, как показано ниже:

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

использование

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.