处理一个空的UITableView。打印友好信息


124

我有一个UITableView在某些情况下为空是合法的。因此,与其显示应用程序的背景图片,不如在屏幕上打印一条友好的消息,例如:

此列表现在为空

最简单的方法是什么?



@oleynikd谢谢!!!!!
卢达

Answers:


173

UITableView的backgroundView属性是您的朋友。

您应该在其中viewDidLoad或任何地方reloadData确定表是否为空,并使用包含UILabel的UIView更新UITableView的backgroundView属性,或者将其设置为nil。而已。

当然,可以使UITableView的数据源承担双重职责,并返回一个特殊的“列表为空”单元格,这让我大吃一惊。突然numberOfRowsInSection:(NSInteger)section不得不计算其他部分的行数,以确保它们也为空。您还需要制作一个包含空消息的特殊单元格。同样不要忘记,您可能需要更改单元格的高度以容纳空消息。这都是可行的,但似乎在创可贴之上是创可贴。


12
我认为backgroundView是最好的解决方案。谢谢!
Ferran Maylinch 2014年

1
一个缺点是,如果将表视图下拉,则消息将停留在其位置上。我希望在应用商店中的应用程序下有更新。这条空消息伴随着滚动行为……
测试了

@testing很明显,如果您需要空的消息来滚动,则不能使用背景视图,因为它不是滚动层次结构的一部分。您可能想将自定义部分和UITableViewCell用于空状态。
LightningStryk

切换backgroundView隐藏属性是必经之路。使用DZNEmptyDataSet,我们必须使用它的emptyDataSetSource
onmyway133

如果要添加按钮,则必须执行以下操作:tableView.backgroundView!.userInteraction = true在该行之后设置tableView.backgroundView = constructMyViewWithButtons(),或者将其设置。
kbpontius '16

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

喜欢扩展名:)
Alix

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
使用扩展名而不是类(不要通过视图控制器)
Cesare

我无法获得上面的代码来为我工作,但是如果其他人遇到相同的问题,我也可以使该答案(第一个)中的代码起作用。此外,我觉得第二个答案会工作,以及(使用场景码头) - stackoverflow.com/questions/28532926/...
蕾妮·奥尔森

viewController.tableView.separatorStyle = .none不需要。
德米特里(Dmitry)

17

我建议使用以下库:DZNEmptyDataSet

在项目中添加它的最简单方法是将其与Cocaopods一起使用,如下所示: 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无法正确垂直对齐的问题。有人遇到过同样的问题吗?
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 2014年

4
我强烈建议不要这样做。它使您的代码充满了边缘情况。
xtravar 2014年

2
@xtravar而不是投票,可以考虑发布您自己的答案。
dasblinkenlight 2014年

1
我一直走这条路,这会导致一系列问题。以我的经验,扩展Apple API总是比尝试替换它们更好。
xtravar 2014年

1
此解决方案不适用于NSFetchedResultsController。我将尝试使用backgroundView方法。
2014年

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的连接,并在适当时(例如,每当重新加载表时)隐藏/显示它。

在此处输入图片说明


那是最简单的方法)!
16

苹果般痛苦的头痛;感谢这个想法
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

基本上,我将添加emptyStateViewtableView对象的子视图。由于分隔符将与视图重叠,因此将其颜色设置为clearColor。要恢复默认的分隔符颜色,您可以将其设置为nil


效果很好!但是,例如,如果您有用于拉动刷新的元素,则此元素不会滚动。我发现最好设置tableHeaderView,并确保将其调整为适合的大小
汉内乐

4

根据Apple的说法,使用Container View Controller是正确的方法。

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

阅读“将子视图控制器添加到您的内容”一章,获取有关如何实现的帮助。

只需确保将子视图框架设置为 (0, 0, tableView.frame.width, tableView.frame.height),即可使所有内容居中并正确对齐。


3

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

背景视图

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

单元格,页眉或页脚以显示消息

这会干扰您的功能代码并引入奇怪的情况。如果您想完美地使您的信息居中,那将增加另一个层次的复杂性。

滚动自己的表视图控制器

您将失去诸如refreshControl之类的内置功能,然后重新发明轮子。坚持使用UITableViewController以获得最佳的可维护结果。

将UITableViewController添加为子视图控制器

我有种感觉,您最终会遇到iOS 7+中的contentInset问题-还有为什么使事情变得复杂?

我的解决方案

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

您必须注意的事项:

  • 表分隔符在reloadData期间的某个时候出现在前面-您需要注意这一点
  • contentInset / contentOffset-在特殊视图上观察那些键
  • 键盘-如果您不希望键盘成为障碍,那是另一种计算方法
  • 自动布局-您不能依赖于框架更改来放置视图

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


您能否详细说明您的答案。您如何判断表格是否为空?然后“相应地采取行动”。
Michael Ozeryansky

您知道您的表是空的,因为您是填充表的那个。因此,在视图控制器中,您将有一个异步加载回调。在该回调中,if(itemsToShow.count == 0){将视图添加到滚动视图}。棘手的部分是使顶视图(“屏蔽/消息视图”)定位为占据滚动视图的整个框架,减去contentInset等,以便消息垂直居中。
xtravar 2014年

如何在表格视图上方添加视图?self.view是表格视图,如果使用addSubView它,它会附加在表格视图上,这总是会导致自动布局出现问题。
测试时间

您放置在表格视图中的视图不应使用自动布局,并且表格视图本身也不使用自动布局。
xtravar 2014年

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

1

在Storyboard中选择TableViewController场景

在此处输入图片说明

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

在此处输入图片说明

在TableViewController上创建UIView的出口(例如,针对yournoDataView)。

并在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

可能不是最大的解决方案,但我只是在表的底部放置了一个标签,如果行= 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时用空的imageview替换标签。–
Zach 2015年

0

最简单,最快的方法是将标签拖到tableView下的侧面板上。为标签和tableView创建出口,并添加if语句以根据需要隐藏和显示标签和表格。或者,您可以将tableView.tableFooterView = UIView(frame:CGRect.zero)添加到您的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
    }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.