Если результатов просмотра таблицы нет, отобразите на экране «Нет результатов»


114

У меня есть tableview, где иногда может не быть результатов для перечисления, поэтому я хотел бы разместить что-то, что говорит «нет результатов», если нет результатов (либо метка, либо одна ячейка представления таблицы?).

Есть ли самый простой способ сделать это?

Я бы попробовать labelза tableviewто спрятать один из двух на основе результатов, но так как я работаю с TableViewControllerи не нормальный , ViewControllerя не знаю , как умный или выполнимо , что есть.

Я также использую Parseи подклассифицирую как PFQueryTableViewController:

@interface TableViewController : PFQueryTableViewController

Я могу предоставить любую дополнительную информацию, просто дайте мне знать!

TableViewController Сцена в раскадровке:

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

РЕДАКТИРОВАТЬ: Per Midhun MP, вот код, который я использую

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger numOfSections = 0;
    if ([self.stringArray count] > 0)
    {
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
        numOfSections                 = 1;
        //yourTableView.backgroundView   = nil;
        self.tableView.backgroundView = nil;
    }
    else
    {
        UILabel *noDataLabel         = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height)];
        noDataLabel.text             = @"No data available";
        noDataLabel.textColor        = [UIColor blackColor];
        noDataLabel.textAlignment    = NSTextAlignmentCenter;
        //yourTableView.backgroundView = noDataLabel;
        //yourTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        self.tableView.backgroundView = noDataLabel;
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }

    return numOfSections;
}

И вот вид, который я получаю, в нем все еще есть разделительные линии. У меня такое ощущение, что это небольшое изменение, но я не уверен, почему появляются разделительные линии?

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


Я думаю, что уловка заключалась в том, чтобы настроить пустой footerView на tableview, чтобы избавиться от строк.
— Бен Синклер,

@ Энди Что ты имеешь в виду?
— SRMR

Не используйте решение, добавленное к этому вопросу. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

Ответы:


206

Вы можете легко добиться этого, используя backgroundViewсвойство UITableView.

Цель C:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger numOfSections = 0;
    if (youHaveData)
    {
        yourTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
        numOfSections                = 1;
        yourTableView.backgroundView = nil;
    }
    else
    {   
        UILabel *noDataLabel         = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, yourTableView.bounds.size.width, yourTableView.bounds.size.height)];
        noDataLabel.text             = @"No data available";
        noDataLabel.textColor        = [UIColor blackColor];
        noDataLabel.textAlignment    = NSTextAlignmentCenter;
        yourTableView.backgroundView = noDataLabel;
        yourTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }

    return numOfSections;
}

Swift:

func numberOfSections(in tableView: UITableView) -> Int
{
    var numOfSections: Int = 0
    if youHaveData
    {
        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 data available"
        noDataLabel.textColor     = UIColor.black
        noDataLabel.textAlignment = .center
        tableView.backgroundView  = noDataLabel
        tableView.separatorStyle  = .none
    }
    return numOfSections
}

Ссылка Ссылка на класс UITableView

backgroundView Свойство

Фоновый вид таблицы.

Декларация

Swift

var backgroundView: UIView?

Objective-C

@property(nonatomic, readwrite, retain) UIView *backgroundView

Обсуждение

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

Вы должны установить для этого свойства значение nil, чтобы установить цвет фона представления таблицы.


Спасибо за ответ! Значит ли это, что мне нужна tableViewрозетка, чтобы я мог делать это yourTableView.backgroundView? Я использую, TableViewControllerпоэтому у меня сейчас нет выхода для него, вот почему мне интересно.
— SRMR

1
UITableViewControllerуже есть свойство с именем, tableViewпоэтому вам не нужно его создавать
— Cihan Tek

Понял, используюself.tableView
— SRMR

1
Коррекция. При дальнейшем тестировании мне действительно пришлось заставить указанную мной строку возвращать то же значение. numOfSections = 1. Если я сделаю его нулевым и мое табличное представление будет пустым, оно будет работать, но когда я создаю ячейку, а затем удаляю ее, вместо удаления и отображения сообщения происходит сбой со следующей ошибкой. *** Завершение работы приложения из-за неперехваченного исключения «NSInternalInconsistencyException», причина: «Внутренняя ошибка UITableView: невозможно создать новую карту разделов со старым количеством разделов: 1 и новым количеством разделов: 0». Я не знаю, почему возвращается одно и то же значение, но оно работает и работает так, как должно.
— ChrisOSX

2
Не используйте это решение. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

107

Для Xcode 8.3.2 - Swift 3.1

Вот не очень известный, но невероятно простой способ добавления представления «Без элементов» к представлению пустой таблицы, которое восходит к Xcode 7. Я оставлю его вам управлять той логикой, которая добавляет / удаляет в фоновое представление таблицы, но вот последовательность действий для раскадровки и Xcode (8.3.2):

  1. Выберите сцену в раскадровке, в которой есть вид таблицы.
  2. Перетащите пустой UIView в «Док сцены» этой сцены.

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

  1. Добавьте UILabel и любые ограничения в новое представление, а затем создайте IBOutlet для этого представления.

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

  1. Назначьте это представление tableView.backgroundView

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

  1. Узрите волшебство!

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

В конечном итоге это работает в любое время, когда вы хотите добавить простое представление к своему контроллеру представления, которое не обязательно должно отображаться немедленно, но которое вы также не хотите передавать код.


1
Этот метод работает для всего, для чего вам нужен простой вид. Я также использовал его для пользовательских заголовков разделов таблицы. На самом деле, вы можете использовать его для всего, для чего вам нужен вид. Просто сделайте ссылку через IBOutlet и добавьте его как подпредставление в любое место, где вам нужно настраиваемое представление.
— Поль Бонневиль

Как сказал @gmogames, после 2 лет работы с IOS, это первый раз, когда я узнаю о фоне tableView! спасибо человек
— Али Адиль

1
Спасибо за это. Чтобы разместить это там, мне пришлось использовать tableView.separatorStyle = .none и изменить размер UIView по умолчанию, чтобы увидеть backgroundView. Я использую Xcode 9.4 со Swift 4.
— Хаммад Тарик

Как разместить настраиваемый вид?
— Nol4635 02

1
@ Nol4635 В случае фона табличного представления вы просто назначаете представление, которое вы создали как IBOutlet, фону табличного представления или, если вы просто хотите добавить представление к любому другому представлению, вы можете просто добавить его как подпредставление. Вам нужно будет установить значения кадра, но это похоже на любое другое представление.
— Поль Бонневиль

30

Быстрая версия приведенного выше кода: -

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    var numOfSection: NSInteger = 0

    if CCompanyLogoImage.count > 0 {

        self.tableView.backgroundView = nil
        numOfSection = 1


    } else {

        var noDataLabel: UILabel = UILabel(frame: CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height))
        noDataLabel.text = "No Data Available"
        noDataLabel.textColor = UIColor(red: 22.0/255.0, green: 106.0/255.0, blue: 176.0/255.0, alpha: 1.0)
        noDataLabel.textAlignment = NSTextAlignment.Center
        self.tableView.backgroundView = noDataLabel

    }
    return numOfSection
}

Но если вы загружаете информацию из JSON, вам нужно проверить, является ли JSON пустым или нет, поэтому, если вы поместите такой код, он сначала покажет сообщение «Нет данных», а затем исчезнет. Потому что после перезагрузки таблицы данные скрываются. Таким образом, вы можете поместить этот код в место загрузки данных JSON в массив. ТАК :-

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

    return 1
}

func extract_json(data:NSData) {


    var error: NSError?

    let jsonData: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers , error: &error)
    if (error == nil) {
        if let jobs_list = jsonData as? NSArray
        {
            if jobs_list.count == 0 {

                var noDataLabel: UILabel = UILabel(frame: CGRectMake(0, 0, self.tableView.bounds.size.width, self.tableView.bounds.size.height))
                noDataLabel.text = "No Jobs Available"
                noDataLabel.textColor = UIColor(red: 22.0/255.0, green: 106.0/255.0, blue: 176.0/255.0, alpha: 1.0)
                noDataLabel.textAlignment = NSTextAlignment.Center
                self.tableView.backgroundView = noDataLabel

            }

            for (var i = 0; i < jobs_list.count ; i++ )
            {
                if let jobs_obj = jobs_list[i] as? NSDictionary
                {
                    if let vacancy_title = jobs_obj["VacancyTitle"] as? String
                    {
                        CJobTitle.append(vacancy_title)

                        if let vacancy_job_type = jobs_obj["VacancyJobType"] as? String
                        {
                            CJobType.append(vacancy_job_type)

                            if let company_name = jobs_obj["EmployerCompanyName"] as? String
                            {
                                CCompany.append(company_name)

                                    if let company_logo_url = jobs_obj["EmployerCompanyLogo"] as? String
                                    {
                                        //CCompanyLogo.append("http://google.com" + company_logo_url)

                                        let url = NSURL(string: "http://google.com" + company_logo_url )
                                        let data = NSData(contentsOfURL:url!)
                                        if data != nil {
                                            CCompanyLogoImage.append(UIImage(data: data!)!)
                                        }

                                        if let vacancy_id = jobs_obj["VacancyID"] as? String
                                        {
                                            CVacancyId.append(vacancy_id)

                                        }

                                    }

                            }

                        }
                    }
                }
            }
        }
    }
    do_table_refresh();


}

func do_table_refresh() {

    dispatch_async(dispatch_get_main_queue(), {
        self.tableView.reloadData()
        return
    })
}

Это очень хорошо работает для отображения метки, когда в строках нет данных. Однако как лучше всего поступать, когда данные поступают и self.tableView.reloadData()вызываются? Я обнаружил, что он добавляет мои новые строки, но noDataLabelпод ними все еще отображается.
— tylerSF

1
Если в вашем массиве есть элемент, просто установите self.tableView.backgroundView = nil
— Чатуранга Сильва

if jobs_list.count == 0 {// добавить указанный выше код} else {self.tableView.backgroundView = nil}
— Чатуранга Сильва,

идеальный. добавление self.tableView.backgroundView = nilв мой оператор if раньше return jobs_list.count работает хорошо. спасибо
— tylerSF

Не используйте в этом ответе первое решение. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

6

Вы можете попробовать этот элемент управления. Это довольно аккуратно. DZNEmptyDataSet

Или на вашем месте все, что я сделал бы, это

  • Проверьте, пуст ли ваш массив данных
  • Если он пуст, добавьте к нему один объект с именем @ "Нет данных".
  • Отобразить эту строку в cell.textLabel.text

Очень просто


5

Swift 3 (обновлено):

override func numberOfSections(in tableView: UITableView) -> Int {
    if myArray.count > 0 {
        self.tableView.backgroundView = nil
        self.tableView.separatorStyle = .singleLine
        return 1
    }

    let rect = CGRect(x: 0,
                      y: 0,
                      width: self.tableView.bounds.size.width,
                      height: self.tableView.bounds.size.height)
    let noDataLabel: UILabel = UILabel(frame: rect)

    noDataLabel.text = "Custom message."
    noDataLabel.textColor = UIColor.white
    noDataLabel.textAlignment = NSTextAlignment.center
    self.tableView.backgroundView = noDataLabel
    self.tableView.separatorStyle = .none

    return 0
}

Не используйте это решение. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

Я согласен. Это решение можно улучшить, но его тоже можно использовать.
— Теодор Чурару

Как вы можете согласиться с тем, что вам не следует использовать это решение, но затем заявите, что его также можно использовать? Это противоречие.
— rmaddy

Я согласен с тем, что это решение можно улучшить, но в его текущем состоянии оно также будет работать.
— Теодор Чурару

5

Swift3.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;
        }

Не используйте это решение. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

3

Я думаю, что самый элегантный способ решить вашу проблему - это переключиться с a UITableViewControllerна a, UIViewControllerкоторое содержит UITableView. Таким образом, вы можете добавить все, UIViewчто хотите, в качестве подвидов основного представления.

Я бы не рекомендовал использовать для этого UITableViewCell, вам может потребоваться добавить дополнительные вещи в будущем, и все может быстро стать некрасивым.

Вы также можете сделать что-то подобное, но это тоже не лучшее решение.

UIWindow* window = [[UIApplication sharedApplication] keyWindow];
[window addSubview: OverlayView];

Спасибо за цвет, который является наиболее элегантным способом реализации, всегда хороший способ подумать об этом. Я могу попробовать изменить раскадровку, чтобы использовать файл, UIViewControllerсодержащий UITableView.
— SRMR

1
Это наиболее перспективный способ. Я сам никогда не использовал его UITableViewController, потому что использовать его не намного проще, чем делать наоборот, но он ограничивает вашу способность что-то менять в будущем.
— Cihan Tek

Это не гарантия будущего, если у вас полупрозрачные стержни. Я настоятельно не рекомендую. По крайней мере, создайте UIViewController, который содержит UITableViewController и соответствующим образом настраивает вещи.
— xtravar

3

Используйте этот код в своем numberOfSectionsInTableViewметоде: -

if ([array count]==0
{

    UILabel *fromLabel = [[UILabel alloc]initWithFrame:CGRectMake(50, self.view.frame.size.height/2, 300, 60)];                                                                                        
    fromLabel.text =@"No Result";
    fromLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;
    fromLabel.backgroundColor = [UIColor clearColor];
    fromLabel.textColor = [UIColor lightGrayColor];
    fromLabel.textAlignment = NSTextAlignmentLeft;
    [fromLabel setFont:[UIFont fontWithName:Embrima size:30.0f]];
    [self.view addSubview:fromLabel];
    [self.tblView setHidden:YES];
}

1
Не используйте это решение. Методы источника данных табличного представления никогда не должны делать больше, чем они должны делать. numberOfSectionsдолжен вернуть счет, и все. То же самое для numberOfRowsInSection. Их можно вызывать много раз в любое время. Никогда не обновляйте представления, не обновляйте данные и не делайте ничего, кроме возврата счетчика. Логика обновления представлений никогда не должна быть в этих методах.
— rmaddy

2

SWIFT 3

        let noDataLabel: UILabel     = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
        noDataLabel.text             = "No data available"
        noDataLabel.textColor        = UIColor.white
        noDataLabel.font             = UIFont(name: "Open Sans", size: 15)
        noDataLabel.textAlignment    = .center
        tableView.backgroundView = noDataLabel
        tableView.separatorStyle = .none

2

Если вы не используете нижний колонтитул tableview и не хотите, чтобы tableview заполнял экран пустыми ячейками таблицы по умолчанию, я бы посоветовал вам установить нижний колонтитул tableview на пустой UIView. Я не знаю правильного синтаксиса для этого в obj-c или Swift, но в Xamarin.iOS я бы сделал это так:

public class ViewController : UIViewController
{
    UITableView _table;

    public ViewController (IntPtr handle) : base (handle)
    {
    }

    public override void ViewWillAppear(bool animated) {
        // Initialize table

        _table.TableFooterView = new UIView();
    }
}

Приведенный выше код приведет к просмотру таблицы без пустых ячеек


2

Вот решение, которое сработало для меня.

  1. Добавьте следующий код в новый файл.

  2. Измените класс таблицы на пользовательский класс MyTableView из раскадровки или .xib

(это будет работать только для первого раздела. Если вы хотите настроить больше, внесите соответствующие изменения в функцию MyTableView reloadData () для других разделов)

public class MyTableView: UITableView {

    override public func reloadData() {
        super.reloadData()

        if self.numberOfRows(inSection: 0) == 0 {
            if self.viewWithTag(1111) == nil {
                let noDataLabel = UILabel()
                noDataLabel.textAlignment = .center
                noDataLabel.text = "No Data Available"
                noDataLabel.tag = 1111
                noDataLabel.center = self.center
                self.backgroundView = noDataLabel
            }

        } else {
            if self.viewWithTag(1111) != nil {
                self.backgroundView = nil
            }
        }
    }
}

Это хороший подход. Я добавил несколько улучшений, чтобы сделать его более округлым. 1. Кэшировать стиль разделителя tableview и восстанавливать его при переходе между пустым / непустым состоянием, чтобы сделать этот подкласс применимым для случаев использования, в которых требуются разные стили разделителей. 2. Добавьте @IBInspectable var emptyStateText: String?и отметьте этот класс, так как @IBDesignableтогда вы сможете изменить другой текст пустого состояния для разных сцен в раскадровке или xibs. Наслаждайтесь! :)
— Эгист Ли

1

Я бы представил представление наложения, которое имеет вид и сообщение, которое вы хотите, если представление таблицы не имеет результатов. Вы можете сделать это в ViewDidAppear, чтобы у вас были результаты до того, как отображать / не отображать представление.


1

Если вы хотите сделать это без кода, попробуйте это!

Нажмите на свой tableView.

tableView Скриншот

Измените стиль с «простого» на «сгруппированный».

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

Теперь, когда вы используете ....

tableView.backgroundView = ВСТАВЬТЕ ЭТИКЕТКУ ИЛИ ПРОСМОТРЕТЬ

Он не покажет разделители!


1

Добавьте этот код в один файл и измените тип коллекции на CustomCollectionView.

import Foundation

class CustomCollectionView: UICollectionView {

  var emptyModel = EmptyMessageModel()
  var emptyView: EmptyMessageView?
  var showEmptyView: Bool = true

  override func reloadData() {
    super.reloadData()

    emptyView?.removeFromSuperview()
    self.backgroundView = nil

    if !showEmptyView {
      return
    }

    if numberOfSections < 1 {
      let rect = CGRect(x: 0,
                        y: 0,
                        width: self.bounds.size.width,
                        height: self.bounds.size.height)

      emptyView = EmptyMessageView()
      emptyView?.frame = rect
      if let emptyView = emptyView {
        //                self.addSubview(emptyView)
        self.backgroundView = emptyView
      }
      emptyView?.setView(with: emptyModel)

    } else {
      emptyView?.removeFromSuperview()
      self.backgroundView = nil
    }
  }
}

class EmptyMessageView: UIView {

  @IBOutlet weak var messageLabel: UILabel!
  @IBOutlet weak var imageView: UIImageView!

  var view: UIView!

  override init(frame: CGRect) {
    super.init(frame: frame)
    xibSetup()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    xibSetup()
  }

  func xibSetup() {
    view = loadViewFromNib()

    view.frame = bounds

    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    addSubview(view)
  }

  func loadViewFromNib() -> UIView {

    let bundle = Bundle(for: type(of: self))
    let nib = UINib(nibName: "EmptyMessageView", bundle: bundle)
    let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

    return view
  }

  func setView(with model: EmptyMessageModel) {
    messageLabel.text = model.message ?? ""
    imageView.image = model.image ?? #imageLiteral(resourceName: "no_notification")
  }
}

///////////
class EmptyMessageModel {
  var message: String?
  var image: UIImage?

  init(message: String = "No data available", image: UIImage = #imageLiteral(resourceName: "no_notification")) {
    self.message = message
    self.image = image
  }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.