Postcard place using Stretchy header in Xamarin.iOS

A year ago I have published a public repository on how to create a stretchy header using Xamarin.iOS application. This time I decided to go a little further with this solution, by preparing it to be able to be rebranded. For now let’s look at how to implement this sassy component.

The app is postcard for places and for this demo I chose to write about my favorite city by far. Full implementation can be previewed on (Github Code).

Create TableView with source and delegate separate

Lets start with creating a TableView and presenting the data with TableViewDataSource and TableViewDelegate by providing custom cells that will contain the Header and the Content for the postcard. The Heather is chosen to be a photo and the Content is information, both about the city.

TableViewDataSource

public class TableViewDataSource : UITableViewDataSource
{
    private const int numberOfRowsInSection = 1;

    public override UITableViewCell GetCell(UITableView tableView, 
                                            NSIndexPath indexPath)
    {
         return tableView.DequeueReusableCell(TableViewContentCell.Key) as
                               TableViewContentCell ?? 
                               TableViewContentCell.Create();
    }

    public override nint RowsInSection(UITableView tableView,
                                       nint section) 
    {
         return numberOfRowsInSection;
    }
}

TableViewDelegate

public class TableViewDelegate : UITableViewDelegate
{
   public override nfloat EstimatedHeight(UITableView tableView,
                                          Foundation.NSIndexPath indexPath)
   {
        return tableView.RowHeight;
   }

   public override nfloat GetHeightForRow(UITableView tableView, 
                                          Foundation.NSIndexPath indexPath)
   {
        return UITableView.AutomaticDimension;
   }
}

Add the Stretchy Header to the TableView

To achieve a transparency at the top of the screen the header has to be added as subview in the TableView. By doing this, the header goes above the content in the TableView and in this scenario they are overlapping. Next step is to push down the content by managing the ContentOffset and ContentInset of the TableView. In this demo the Header size is 300. After these steps proper position of the elements in the view is achieved.

TableView.DataSource = new TableViewDataSource();


TableView.Delegate = new TableViewDelegate();


tableViewHeaderCell = TableView.DequeueReusableHeaderFooterView(
                                 TableViewHeaderCell.Key) 
                                 as TableViewHeaderCell ?? 
                                 TableViewHeaderCell.Create();

tableViewHeaderCell.UserInteractionEnabled = true;

TableView.TableHeaderView = null;


TableView.AddSubview(tableViewHeaderCell);

To achieve the effect of stretching the header rectangle, a variable called effectiveHeight have to be created. The effectiveHeight is fixed size which is the initial height of the header. What is important for the header is to change the content mode to Aspect Fill so it will scale the content to fit the size of itself by changing the aspect ratio of the content.

The following code represents the ability of the header to adapt its size to the changes done while scrolling. As proposed the header is the default size when there is no movement. By scrolling, the header height is supposed to increase by adding the difference between the offset and the effectiveHeight. If the absolute value of the offset is smaller than the effectiveHeight no changes will occur. And simple as that we are done with the logic.

public void UpdateHeaderView()
{
    var headerRect = new CGRect(0,
                                -effectiveHeight,
                                UIScreen.MainScreen.Bounds.Width,
                                TABLE_HEADER_VIEW_HEIGHT);

    if (TableView.ContentOffset.Y < -effectiveHeight)
    {
           headerRect.Y = TableView.ContentOffset.Y;
           headerRect.Height = (-TableView.ContentOffset.Y);
    }

    tableViewHeaderCell.Frame = headerRect;
       
 }

Invoke method in scroll event of the TableView

As said above, this happens on scrolling the TableView. So, next create an event which will listen to table scroll and invoke it on the Scrolled method in the TableViewDelegate, than attach it on the TableView.

public delegate void DidScrollEventHandler();

public event DidScrollEventHandler DidTableScrolled;

public override void Scrolled(UIScrollView scrollView)
{
    DidTableScrolled();
}

MainTableViewController

tableViewDelegate.DidTableScrolled += UpdateHeaderView;

After doing all these steps, what is left is to compile, run your app, and watch this beautiful effect happening. 

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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