【问题标题】:Handling an empty UITableView. Print a friendly message处理一个空的 UITableView。打印友好消息
【发布时间】:2013-03-22 17:20:07
【问题描述】:

我有一个 UITableView,在某些情况下它为空是合法的。所以而不是显示 应用程序的背景图片,我更喜欢在屏幕上打印一条友好的消息,例如:

这个列表现在是空的

最简单的方法是什么?

【问题讨论】:

标签: iphone ios uitableview uiview


【解决方案1】:

UITableView 的 backgroundView 属性是你的朋友。

viewDidLoadreloadData 的任何地方,您应该确定您的表是否为空,并使用包含 UILabel 的 UIView 更新 UITableView 的 backgroundView 属性,或者将其设置为 nil。就是这样。

当然可以让 UITableView 的数据源执行双重任务并返回一个特殊的“列表为空”单元格,这让我觉得很麻烦。突然,numberOfRowsInSection:(NSInteger)section 必须计算其他部分的行数,以确保它们也是空的。您还需要制作一个包含空消息的特殊单元格。另外不要忘记您可能需要更改单元格的高度以容纳空消息。这一切都是可行的,但它似乎是创可贴之上的创可贴。

【讨论】:

  • 我认为 backgroundView 是最好的解决方案。谢谢!
  • 一个缺点是如果表格视图被拉下,消息会停留在它的位置上。我宁愿有喜欢在app store 下的app 更新。这里的空消息伴随着滚动行为......
  • @testing 显然,如果您需要空消息来滚动,则不能使用背景视图,因为这不是滚动层次结构的一部分。您可能希望使用自定义部分和 UITableViewCell 作为空状态。
  • 切换backgroundView隐藏属性是要走的路。对于DZNEmptyDataSet,我们必须使用它的emptyDataSetSource
  • 如果你想添加按钮,你必须在你设置tableView.backgroundView = constructMyViewWithButtons()的那一行之后:tableView.backgroundView!.userInteraction = true,或者你设置它。
【解决方案2】:

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

【讨论】:

  • 感谢您的建议。
  • 扩展更好!谢谢。
  • 喜欢这个扩展 :)
  • 如果您有部分,那么您需要将此逻辑移至 func numberOfSections(in tableView: UITableView) -> Int 方法
【解决方案3】:

根据此处的答案,这是我制作的快速课程,您可以在 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/ 的帮助下

【讨论】:

  • 也想给它添加图片。但这是一个很好的快速解决方案。
  • 使用扩展而不是类(不要传递视图控制器)
  • 我无法让上面的代码为我工作,但我能够让这个答案(第一个)中的代码工作,以防其他人有同样的问题。另外我认为第二个答案也可以(使用场景码头)-stackoverflow.com/questions/28532926/…
  • viewController.tableView.separatorStyle = .none 不是必需的。
【解决方案4】:

我推荐以下库:DZNEmptyDataSet

将它添加到项目中的最简单方法是将它与 Cocoopods 一起使用,如下所示:pod 'DZNEmptyDataSet'

在您的 TableViewController 中添加以下导入语句 (Swift):

import DZNEmptyDataSet

然后确保你的类符合 DNZEmptyDataSetSourceDZNEmptyDataSetDelegate 像这样:

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 没有正确垂直对齐的问题。有人遇到过同样的问题吗?
【解决方案5】:

一种方法是修改您的数据源以在行数为零时返回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 实例对其进行设置。

【讨论】:

  • 我在处理使用deleteRowsAtIndexPaths:withRowAnimation: 删除行的表时遇到了问题,因为numberOfRowsInSection 返回的数字需要与$numRows - $rowsDeleted 的结果相匹配。
  • 我强烈,强烈建议不要这样做。它使您的代码充满了边缘情况。
  • @xtravar 与其投反对票,不如考虑发布您自己的答案。
  • 我一直在走这条路,它会导致一系列问题。根据我的经验,增加 Apple API 几乎总是比尝试替换它们更好。
  • 此解决方案不适用于 NSFetchedResultsController。我将尝试使用 backgroundView 方法。
【解决方案6】:

我一直在为此使用 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;
}

【讨论】:

  • 不错的技巧,对我来说似乎很干净。这是一条线:return tableView.numberOfRowsInSection(section) == 0 ? "This list is now empty" : nil
【解决方案7】:

我只能建议在单元格之后将 UITextView 拖放到 TableView 中。与 ViewController 建立连接并在适当的时候隐藏/显示它(例如,每当重新加载表格时)。

【讨论】:

  • 这是最简单的方法)!
  • 苹果这样的头痛;感谢这个想法
【解决方案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
     }
}

【讨论】:

    【解决方案9】:

    使用 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,并确保it resizes to fit
    【解决方案10】:

    根据Apple,使用容器视图控制器是正确的方法。

    我将所有空状态视图放在单独的 Storyboard 中。每个都在它自己的 UIViewController 子类下。我直接在他们的根视图下添加内容。如果需要任何操作/按钮,您现在已经有了一个控制器来处理它。
    然后只需从该 Storyboard 实例化所需的视图控制器,将其添加为子视图控制器并将容器视图添加到 tableView 的层次结构(子视图)。 您的空状态视图也将是可滚动的,这感觉很好,并允许您实现拉动刷新。

    Read 章节“将子视图控制器添加到您的内容”以获取有关如何实施的帮助。

    只需确保将子视图框架设置为 (0, 0, tableView.frame.width, tableView.frame.height) 并且事物将正确居中和对齐。

    【讨论】:

      【解决方案11】:

      这是最好和最简单的解决方案。

      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;
      

      【讨论】:

        【解决方案12】:

        首先,其他流行方法的问题。

        背景视图

        如果您要使用将其设置为 UILabel 的简单情况,背景视图不会很好地居中。

        用于显示消息的单元格、页眉或页脚

        这会干扰您的功能代码并引入奇怪的边缘情况。如果您想完美地集中您的信息,这会增加另一个级别的复杂性。

        滚动你自己的表格视图控制器

        您失去了内置功能,例如 refreshControl,并重新发明了轮子。坚持使用 UITableViewController 以获得最佳的可维护结果。

        将 UITableViewController 添加为子视图控制器

        我感觉您最终会在 iOS 7+ 中遇到 contentInset 问题 - 以及为什么要让事情复杂化?

        我的解决方案

        我想出的最佳解决方案(当然,这并不理想)是制作一个特殊的视图,它可以位于滚动视图的顶部并采取相应的行动。这在 iOS 7 中显然会因为 contentInset 疯狂而变得复杂,但它是可行的。

        注意事项:

        • 在 reloadData 期间,表格分隔符有时会出现在前面 - 您需要防止这种情况发生
        • contentInset/contentOffset - 在您的特殊视图中观察这些键
        • 键盘 - 如果您不希望键盘妨碍您,那就另当别论了
        • 自动布局 - 您不能依赖帧更改来定位视图

        一旦你在一个 UIView 子类中弄清楚了这一点,你就可以将它用于所有事情 - 加载微调器、禁用视图、显示错误消息等。

        【讨论】:

        • 您能否详细说明您的答案。如何判断表是否为空?然后“采取相应的行动”。
        • 你知道你的桌子是空的,因为你是填充你的桌子的人。所以在你的视图控制器中,你会有一个异步加载回调。在该回调中,if(itemsToShow.count == 0) {将您的视图添加到滚动视图}。棘手的部分是使顶视图(“屏蔽/消息视图”)定位为占据滚动视图的整个框架,减去 contentInset 等,以便消息垂直居中。
        • 如何在表格视图之上添加视图? self.view 是表格视图,如果我使用addSubView,它会附加到表格视图,这总是会导致自动布局出现问题。
        • 你放置在table view中的view不应该使用autolayout,tableview本身也不使用autolayout。
        • 你错过了一种方法;您可以使用 UITableViewController 并将其作为子视图控制器添加到常规 UIViewController
        【解决方案13】:

        您可以将它添加到您的 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)
        }
        

        在从 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 函数是什么样的?
        • 嗨,@Saamer 我刚刚更新了上面的答案。感谢您指出这一点,希望这会有所帮助:)
        【解决方案14】:

        多个数据集和部分有一个特定的用例,您需要为每个部分设置一个空状态。

        您可以使用此问题的多个答案中提到的建议 - 提供自定义的空状态单元格。

        我将尝试以编程方式更详细地引导您完成所有步骤,希望对您有所帮助。这是我们可以期待的结果:

        为简单起见,我们将使用 2 个数据集(2 个部分),它们将是静态的。

        我还将假设您的 tableView 逻辑的其余部分与数据集、tabvleView 单元格和部分正常工作。

        Swift 5,让我们开始吧:

        1.创建自定义空状态 UITableViewCell 类:

        class EmptyTableViewCell: UITableViewCell {
        
            override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
                super.init(style: style, reuseIdentifier: reuseIdentifier)
                setupView()
            }
        
            required init?(coder: NSCoder) {
                fatalError("init(coder:) has not been implemented")
            }
        
            let label: UILabel = {
                let label = UILabel()
                label.translatesAutoresizingMaskIntoConstraints = false
                label.text = "Empty State Message"
                label.font = .systemFont(ofSize: 16)
                label.textColor = .gray
                label.textAlignment = .left
                label.numberOfLines = 1
                return label
            }()
        
            private func setupView(){
                contentView.addSubviews(label)
                let layoutGuide = contentView.layoutMarginsGuide
                NSLayoutConstraint.activate([
                    label.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor),
                    label.topAnchor.constraint(equalTo: layoutGuide.topAnchor),
                    label.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor),
                    label.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor),
                    label.heightAnchor.constraint(equalToConstant: 50)
                ])
            }
        }
        

        2。将以下内容添加到您的 UITableViewController 类以注册您的空单元格:

        class TableViewController: UITableViewController {
            ...
            let emptyCellReuseIdentifier = "emptyCellReuseIdentifier"
            ...
            override func viewDidLoad(){
                ...
                tableView.register(EmptyTableViewCell.self, forCellReuseIdentifier: emptyCellReuseIdentifier)
                ...
            }
        }
        

        3.现在让我们强调一下上面提到的一些假设:

        class TableViewController: UITableViewController {
            // 2 Data Sets
            var firstDataSet: [String] = []
            var secondDataSet: [String] = []
        
            // Sections array
            let sections: [SectionHeader] = [
                .init(id: 0, title: "First Section"),
                .init(id: 1, title: "Second Section")
            ]
            ...
            // MARK: - Table view data source
            override func numberOfSections(in tableView: UITableView) -> Int {
                sections.count
            }
            override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
                return sections[section].title
            }
                ...
            }
        
        struct SectionHeader {
            let id: Int
            let title: String
        }
        

        4.现在让我们在我们的数据源中添加一些自定义逻辑来处理我们部分中的空行。 如果数据集为空,我们将返回 1 行:

        class TableViewController: UITableViewController {
            ...
            // MARK: - Table view data source
            ...
            override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                switch section{
                case 0:
                    let numberOfRows = firstDataSet.isEmpty ? 1 : firstDataSet.count
                    return numberOfRows          
                case 1:
                    let numberOfRows = secondDataSet.isEmpty ? 1 : secondDataSet.count
                    return numberOfRows   
                default:
                    return 0
                }
            }
            ...
        }
        

        5.最后,最重要的“cellForRowAt indexPath”:

        class TableViewController: UITableViewController {
            ...
            // MARK: - Table view data source
            ...
            override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                
                // Handle Empty Rows State
                switch indexPath.section {
                case 0:
                    if firstDataSet.isEmpty {
                        if let cell = tableView.dequeueReusableCell(withIdentifier: emptyCellReuseIdentifier) as? EmptyTableViewCell {
                            cell.label.text = "First Data Set Is Empty"
                            return cell
                        }
                    }
                case 1:
                    if secondDataSet.isEmpty {
                        if let cell = tableView.dequeueReusableCell(withIdentifier: emptyCellReuseIdentifier) as? EmptyTableViewCell {
                            cell.label.text = "Second Data Set Is Empty"
                            return cell
                        }
                    }
                default:
                    break
                }
                
                // Handle Existing Data Sets
                if let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as? TableViewCell {
                    switch indexPath.section {
                    case 0:
                        ...
                    case 1:
                        ...
                    default:
                        break
                    }
                    return cell
                }
        
                return UITableViewCell()
            }
            ...
        }
        

        【讨论】:

          【解决方案15】:

          在情节提要中选择您的 tableviewController 场景

          拖放 UIView 为您的消息添加标签(例如:无数据)

          在您的 TableViewController 上创建 UIView 的出口(例如 yournoDataView)。

          在 viewDidLoad 中

          self.tableView.backgroundView = yourNoDataView

          【讨论】:

            【解决方案16】:

            显示空列表的消息,无论是 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!")
            }
            

            记住: 不要忘记删除消息标签,以防刷新后有数据。

            【讨论】:

            • 如果 messages.count != 0 { show } 我会添加一个 if 条件
            【解决方案17】:

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

            【讨论】:

              【解决方案18】:

              Swift 版本但更好更简单的形式。 **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;
                      }
              

              【讨论】:

                【解决方案19】:

                可能不是最好的解决方案,但我只是通过在表格底部放置一个标签来做到这一点,如果 rows = 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 时将标签替换为空图像视图。
                【解决方案20】:

                最简单快捷的方法是将标签拖到 tableView 下的侧面板上。为 label 和 tableView 创建一个 outlet 并添加 if 语句以根据需要隐藏和显示 label 和 table。或者,您可以将 tableView.tableFooterView = UIView(frame: CGRect.zero) this 添加到 viewDidLoad() 以使空表感觉如果表和背景视图具有相同的颜色,则它是隐藏的。

                【讨论】:

                • (这篇文章似乎没有为问题提供quality answer。请编辑您的答案并用更详细的信息完成它,或者只是将其作为对该问题的评论发布)。
                【解决方案21】:

                我做了一些更改,这样我们就不需要手动检查计数,我还为标签添加了约束,这样无论消息有多大都不会出错,如下所示:

                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
                    }
                

                【讨论】:

                  【解决方案22】:

                  或者您也可以使用一些可定制的轻量级库

                  SwiftEmptyState

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-09-23
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-02-28
                    相关资源
                    最近更新 更多