The Yahoo News Digest app includes a couple of interesting user interface elements that I wanted to use within my own apps. The feature that I was most keen to recreate was the stretching UITableViewHeader. Its an effect seen in lots of iOS (sometimes referred to as a parallax header). As Beer Drinkin is going to support multi-tasking on iOS, I needed to ensure my implementation continues to support Storyboards and Auto Layout. Fortunately it proved very simple to get everything setup. In this blog post I’ll be sharing how I went about implementing it
Setting up the Storyboard
Adding a header view
To get started I opened my existing Storyboard and selected the UIViewController that requires the tableview header. In my case the scene (or view controller) isn’t a UITableViewController because I require a floating ‘Check in’ button to be visible at all times. Its worth noting that all the steps in the tutorial work with both UITableViewControllers and UIViewControllers.
Once I had the storyboard loaded, I dragged a UIView from the toolbox and made sure to insert it above the UITableViewCells as a the header view for the table. I then added a UIImageView to the new UIView and set its constraints to be 0,0,0,0. This way when the parent view (the UIView) resizes, the UIImageView will resize as well. I also made sure to set the UIImageView view mode property to Aspect Fit, which makes sure the image looks great no matter what size the view.
Adding some C#
Adding the resize code
If I were to have run this now, the table header would be displayed but wouldn’t resize with scroll events. To add scaling, I needed to add a code into my ViewController to setup the stretchy goodness that I wanted.
Because I use the header views height in a number of locations throughout the beer description view controller, I went ahead and created a variable rather than scattering magic numbers over my class.[sourcecode language=”csharp”] private nfloat headerViewHeight = 200;
Managing the header view
To allow me to manage the table header, I needed to remove it from the UITableView and keep it as a variable for use later. To do this I created a variable in the beer description view controller.[sourcecode language=”csharp”] private UIView headerView;
When we load the view controller, we’ll want to set our headerView variable and then set the UITableViews header property to null. This means the tableview has no header view to manage anymore, instead I’ve taken control of the view which allows me to ensure it resizes correctly as the table view scrolls.Despite having just removed the header view from the UITableView, I actually want to go ahead and add it to the table view hierarchy (but not as the header view property of the UITableView)[sourcecode langauge =”csharp”] headerView = tableView.TableHeaderView;
tableView.TableHeaderView = null;
tableView.ContentInset = new UIEdgeInsets (headerViewHeight, 0, 0, 0);
tableView.BackgroundColor = UIColor.Clear;
Listening to TableViewDidScroll
In order to successfully respond to the DidScroll event of the UITableViewSource, I’ll need to create an event in the table views delegate. This is because of an issue with the UITableView DidScroll event not firing when a delegate has been set.[sourcecode language=”csharp”] public override void Scrolled (UIScrollView scrollView)
public event DidScrollEventHandler DidScroll;
We can now hook up the table DidScroll event with a small piece of logic for resizing the view.[sourcecode language=”csharp”] //Update Tableview
tableView.Source = new BeerDescriptionDataSource(ref cells);
var deleg = new DescriptionDelegate (ref cells);
deleg.DidScroll += UpdateHeaderView;
tableView.Delegate = deleg;
void UpdateHeaderView ()
var headerRect = new CGRect (0, -headerViewHeight, tableView.Frame.Width, headerViewHeight);
if (tableView.ContentOffset.Y &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; -headerViewHeight)
headerRect.Location = new CGPoint (headerRect.Location.X, tableView.ContentOffset.Y);
headerRect.Size = new CGSize (headerRect.Size.Width, -tableView.ContentOffset.Y);
headerView.Frame = headerRect;
Its very easy to use this approach to add resizing animations to any number of controls within your UITableView. My favourite part of this solution is that it works perfectly across all iOS devices and doesn’t force me to drop support of Autolayout.