How do I display a placeholder image when my UITableView has no data yet?

I have an application that, when loaded, displays a UITableView with user data in it.

However, when the user first loads the app (before they created any data), I would like to display a background image instead of an empty table (with an arrow pointing to "add record", a navigation button). After the user adds their first record, a table is displayed instead. I've seen a lot of applications do this - the only example I can currently think of is Cha-Chhing before you have any budgets / etc. I can't get my life to work on how to do it.

I originally added a navigation controller to the main xib window, whose rootViewController was a custom view / xib controller. This rootViewController contained a background image with a hidden table view above it and a custom tableview control that controlled the table view. This seemed to work pretty well and if there is data, it will be loaded and displayed in the table. However, if I were to loop through the data behind the scenes, the application would fail with this error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'*** -[UITextEffectsWindow tableView:cellForRowAtIndexPath:]: unrecognized selector sent to instance 0xd2d130'

      

I don't know what the UITextEffectsWindow is, or why it was trying to manipulate my tableview. I am guessing that something might be wrongly connected in my view hierarchy ...

If there is a much simpler or easier way to do this, I would be very grateful if anyone could explain it. How do you do it?

Thanks in advance.

+1


a source to share


5 answers


So, to solve this, I did it as described in the comments above:

I created a regular UIViewController subclass containing a UIImageView and a UITableView. The viewController conforms to the UITableViewDelegate and UITableViewDatasource protocols and monitors the table view. The viewController class simply shows or hides the image depending on whether data is available.



I was wrong before trying to control both views with a UITableViewController. A UITableViewController must have a tableView as its view, whereas with this solution, a viewController can contain both an image and a tableView and implement the necessary protocols for manipulating the tableView.

Thanks for the help!

0


a source


Here's one solution I'm happy with.

I first created a transparent view that was the same size as my TableView. I am adding this view as a child of the TableView when the TableView datasource has no data. I completely remove the view when data is available as transparency can affect the smoothness of scrolling animations with TableViews.



I just added a transparent label to this view that says something about the impact of "No data". Adding a little shading to this label really helped solidify the concept that the label was "floating" on top of an empty TableView.

I like your method of using the image. Done correctly, it might save you some work if you don't need to localize the string as I am currently doing.

+1


a source


To achieve this by subclassing UITableViewController as the only view (inside a UINavigationController according to Apple's template), I used the following approach:

  • Create a UIView for the size of my tableView in XIB which contains your UITableViewController and tableView.

  • Add an ImageView set with my sample placeholder to the UIView.

  • Connect the UIView as an IBOutlet (in the code example below, I named it emptyTableView)

  • When it's time to show the placeholder from the UITableViewController subclass:

    [self.tableView addSubView: emptyTableView]; [self.tableView setScrollEnabled: FALSE];

Disabling scrolling is necessary otherwise the user can move the placeholder image up and down. Just remember to enable it as soon as the user adds the item.

  1. To remove an image view

    [emptyTableView removeFromSuperview];

+1


a source


For this, I am using the following controller instead UITableViewController

. It will automatically place the view on top of the table when it is empty and delete it when it is full.

Just call [self reloadData]

instead [self.tableView reloadData]

so it can check if the table has become empty.

In your subclass, implement a function makeEmptyOverlayView

that will create a view displayed above an empty table.

@interface MyTableViewController : UITableViewController
{
      BOOL hasAppeared;
      BOOL scrollWasEnabled;
      UIView *emptyOverlay;
}

- (void) reloadData;
- (void) checkEmpty;

@end

@implementation MyTableViewController

- (void)viewWillAppear:(BOOL)animated
{
   [self reloadData];
   [super viewWillAppear: animated];
}

- (void)viewDidAppear:(BOOL)animated
{
   hasAppeared = YES;

   [super viewDidAppear: animated];

   [self checkEmpty];
}

- (void)viewDidUnload
{
   if (emptyOverlay)
   {
      self.tableView.scrollEnabled = scrollWasEnabled;
      [emptyOverlay removeFromSuperview];
      emptyOverlay = nil;
   }
}

- (void) reloadData
{
   [self.tableView reloadData];

   if (hasAppeared &&
       [self respondsToSelector: @selector(makeEmptyOverlayView)])
      [self checkEmpty];
}

- (void) checkEmpty
{
   BOOL isEmpty(YES);

   id<UITableViewDataSource> src(self.tableView.dataSource);
   NSInteger sections(1);
   if ([src respondsToSelector: @selector(numberOfSectionsInTableView:)])
      sections = [src numberOfSectionsInTableView: self.tableView];
   for (int i(0); i<sections; ++i)
   {
      NSInteger rows([src tableView: self.tableView numberOfRowsInSection: i]);
      if (rows)
         isEmpty = NO;
   }

   if (!isEmpty != !emptyOverlay)
   {
      if (isEmpty)
      {
         scrollWasEnabled = self.tableView.scrollEnabled;
         self.tableView.scrollEnabled = NO;
         emptyOverlay = [self makeEmptyOverlayView];
         [self.tableView addSubview: emptyOverlay];
         [emptyOverlay release];
      }
      else
      {
         self.tableView.scrollEnabled = scrollWasEnabled;
         [emptyOverlay removeFromSuperview];
         emptyOverlay = nil;
      }
   }
   else if (isEmpty)
   {
      // Make sure it is still above all siblings.
      [emptyOverlay retain];
      [emptyOverlay removeFromSuperview];
      [self.tableView addSubview: emptyOverlay];
      [emptyOverlay release];
   }
}

@end

      

+1


a source


If you are using Three20 , you can easily set any image as the placement before filling your table.

0


a source







All Articles