Handling an empty UITableView. Print a friendly me

2019-01-12 16:02发布

I have a UITableView that in some cases it is legal to be empty. So instead of showing the background image of the app, I would prefer to print a friendly message in the screen, such as:

This list is now empty

What is the simplest way to do it?

17条回答
beautiful°
2楼-- · 2019-01-12 16:50

This is the best and simple solution.

    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;
查看更多
混吃等死
3楼-- · 2019-01-12 16:52

UITableView's backgroundView property is your friend.

In viewDidLoad or anywhere that you reloadData you should determine if there your table is empty or not and update the UITableView's backgroundView property with a UIView containing a UILabel or just set it to nil. That's it.

It is of course possible to make UITableView's data source do double duty and return a special "list is empty" cell, it strikes me as a kludge. Suddenly numberOfRowsInSection:(NSInteger)section has to compute the number of rows of other sections it wasn't asked about to make sure they are empty too. You also need to make a special cell that has the empty message. Also don't forget that you need to probably change the height of your cell to accommodate the empty message. This is all doable but it seems like band-aid on top of band-aid.

查看更多
The star\"
4楼-- · 2019-01-12 16:52

First, the problems with other popular approaches.

BackgroundView

Background view doesn't center nicely if you were to use the simple case of setting it to be a UILabel.

Cells, headers, or footers to display the message

This interferes with your functional code and introduces weird edge cases. If you want to perfectly center your message, that adds another level of complexity.

Rolling your own table view controller

You lose built-in functionality, such as refreshControl, and re-invent the wheel. Stick to UITableViewController for the best maintainable results.

Adding UITableViewController as a child view controller

I have a feeling you'll end up with contentInset issues in iOS 7+ - plus why complicate things?

My solution

The best solution I've come up with (and, granted, this isn't ideal) is to make a special view that can sit on top of a scroll view and act accordingly. This obviously gets complicated in iOS 7 with contentInset madness, but it's doable.

Things you have to watch out for:

  • table separators get brought to front at some point during reloadData - you need to guard against that
  • contentInset/contentOffset - observe those keys on your special view
  • keyboard - if you don't want the keyboard to get in the way, that's another calculation
  • autolayout - you can't depend on frame changes to position your view

Once you have this figured out once in one UIView subclass, you can use it for everything - loading spinners, disabling views, showing error messages, etc.

查看更多
虎瘦雄心在
5楼-- · 2019-01-12 16:53

Probably not the greatest solution, but I did this by just putting a label at the bottom of my table and if the rows = 0 then I assign it some text. Pretty easy, and achieves what you are trying to do with a few lines of code.

I have two sections in my table (jobs and schools)

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

    if (jobs.count == 0 && schools.count == 0) {
        emptyLbl.text = "No jobs or schools"
    } else {
        emptyLbl.text = ""
    }
查看更多
Rolldiameter
6楼-- · 2019-01-12 16:55

Using the backgroundView is fine, but it does not scroll nicely like in Mail.app.

I did something similar to what xtravar did.

I added a view outside the view hierarchy of the tableViewController. hierarchy

Then i used the following code in 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

Basically I added the emptyStateView as a subview of the tableView object. As the separators would overlap the view, I set their color to clearColor. To get back to the default separator color, you can just set it to nil.

查看更多
登录 后发表回答