Category Archives: iOS

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.

Image

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

Image

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.origin.y-20,
 myframe.size.width,
 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,
                                                                                   myframe.size.width,
                                                                                   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!

horizontalScroll

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];
}

Becoming the Teacher

I have been given a great opportunity to help create the curriculum for an iOS programming course at Noble Desktop.  It will be a three day course focusing on using Xcode and the Interface Builder to create a couple of iOS apps, plus some programming fundamentals thrown in.

The process I am using to create the curriculum is to record a teaching session on my computer which will later get transcribed into the class workbook. I finished recording my first exercise (Hello World!) this week and gave the guys at Noble Desktop 20 minutes worth of video to review. In the video I explain the following:

  • small intro to Xcode
  • how to place a button and label on an iOS view
  • change the text of the label to “Hello World”, when the button is clicked
  • run the app in the iPhone simulator

Screen Shot 2013-01-06 at 2.23.24 PM

I really enjoyed making the video and it forced me to rethink the way I use Xcode. I am  self-taught when it comes to Objective-C and Xcode. I was a Java programmer for YEARS when I decided to pick up a book and program a kids’ game for the iPhone 3 years ago. Therefore, I did a little reading and refreshing before making my first video. I made sure I knew the exact names of all the inspectors and editors. Also, I looked into some of the most convenient ways to use Xcode. I’ve always been lazy about using IDEs– once something works for me, I don’t bother finding out if there is an even easier way. But for this recording, I forced myself to learn the trick to open the file editor and the storyboard editor in a split pane editor. Its called the “Assistant Editor” and its accessed by clicking on the little icon that looks like a tuxedo. I may never go back to the regular editor.  To that point, I think creating this curriculum will make me a better developer. Or at least a better IDE user! Not to mention what I’ll learn when I actually get to teach it to a room full of question-asking newbies. I’m pretty excited.