Table view on top of horizontal scroll view

I created an app with a UITableView main screen. There are about 12 rows in my table each used to describe a particular characteristic of an item for sale, including the ability to upload photos of the item. Simply stated, the user can tap each row to be brought to a detail screen. After entering their selections the user returns to the main table view.


To add photos to an item, you click on the row labeled “More Photos” and are brought to a photo screen like this:


After initial development was complete we decided it would improve usability if the photo details were pulled out from their detail screen to the top level main screen. I need to split the screen into two views: the main table view which scrolls top to bottom, and a persistent horizontal scroll area at the bottom. The main table view will scroll “under” the image scroll view at the bottom. I tried a couple ways to do this which didn’t work:

  • Place a UIScrollView on top of the UITableView so it will cover the bottom part of the screen. Not only did my scroll view not even show up in the simulator (probably hidden beneath the table), I’m certain the bottom of the table would never get a chance to scroll above the horizontal scroll view.
  • Change the height of the UITableViewController tableView in the viewDidLoad event. This did nothing for me. Not sure if the table was already drawn, so perhaps I could not affect the height.
  • Create a ViewController in the Storyboard, place two ContainerView objects on it which automatically create segues to two related view controllers. This did not run in my iPhone 5 Simulator because it complains these types of segues are not available in 5.1 and before. (arg)

SO, lets create my own in the code!

After reading this fantastic tutorial on Containing ViewControllers, I decided to create a Container ViewController which would have two child view controllers (not just child views). I call the containing VC “MyContainerViewController”. In my header file I have two attributes for the child VCs. One for the tableview, “ListItemViewController” and one for adding photos, “MorePhotosViewController”.

@interface MyContainerViewController : UIViewController{
//NSArray *_subViewControllers;
ListItemViewController *listItemViewController;
MorePhotosViewController *morePhotosViewController;

@property (nonatomic, strong) ListItemViewController *listItemViewController;
@property (nonatomic, strong) MorePhotosViewController *morePhotosViewController;

Then in viewDidLoad of my containing view controller, I instantiate and add my two ViewControllers as children. Also, I add each view of the viewControllers as subviews to the ContainingViewController. When I instantiate the tableview, I change the height to allow for the new horizontal scroll view which will set below it.

listItemViewController = [[ListItemViewController alloc] init];

//Grab the dimensions of the container view.
CGRect myframe = [self.view frame];

//Set the tableview to be 190 pixels shorter than the full view. 
//Also Leave a little room at top for the nav bar
[listItemViewController.tableView setFrame:CGRectMake(myframe.origin.x,
 myframe.size.height - 190 )];

//ScrollView is created and sized within the child VC's viewDidLoad method
morePhotosViewController = [[MorePhotosViewController alloc] init];

// add as child VC
[self addChildViewController:listItemViewController];

// add it to container view
[self.view addSubview:listItemViewController.view];

// add as child VC
[self addChildViewController:morePhotosViewController];

// add it to container view
[self.view addSubview:morePhotosViewController.view];

In the viewDidLoad method of my horizontal scroll view, MorePhotosViewContoller, I create a scrollview, size it and add it as a subview

CGRect myframe = [self.view frame];
    UIScrollView *imageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(myframe.origin.x,
                                                                                   myframe.size.height - 190,
                                                                                   190 )];

    imageScrollView.contentSize = CGSizeMake(myframe.size.width*2, 190);
    imageScrollView.showsHorizontalScrollIndicator = YES;
    //  imageScrollView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:imageScrollView];

I also add a bunch of image placeholders for the user to click on to “add a photo”.

The last step is to replace my original tableview in the navigation hierarchy with my containing VC. So I go to the storyboard and do just that. I make MyContainerViewController the rootViewController for my NavigationController. And here is the result!


Looks great, but there is one problem. All of the table cells that fall below the photo bar at the bottom do not respond to taps once they scroll into view! The way I solved this is to grab all the tap events for the table view through a gesture recognizer, determine which row the user tapped and trigger the selection event myself. A little hacky? Not too bad, I think.

- (void)tapped:(UIGestureRecognizer *)gestureRecognizer
    CGPoint point = [gestureRecognizer locationInView:self.tableView];

    CGFloat theRowHeight = [self.tableView rowHeight];

    CGRect btnCurrentFrame = CGRectMake(self.btnSave.frame.origin.x, (self.btnSave.frame.origin.y + self.tableView.contentOffset.y),self.btnSave.frame.size.width,self.btnSave.frame.size.height);

    CGFloat theRowNum = point.y / theRowHeight;
    float roundedRowNum = ceilf(theRowNum);
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(roundedRowNum-1) inSection:0];

    [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [self tableView:self.tableView didSelectRowAtIndexPath:indexPath];


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s