I've been trying for quite awhile to build a parallax-style table view header that's comprised of an image, similar to the Yahoo News Digest App, or when viewing a business in Maps.app. (When you rubber-band the table the image height grows, and when scrolling down the image appears to scroll slightly slower).
Here's an demonstrative video courtesy of APParallaxHeader:
https://www.youtube.com/watch?v=7-JMdapWXGU
The best tutorial I was able to find was this tutorial, which basically consists of adding the image view as a subview of the table view. While that mostly works, adding as a subview to UITableView
is pretty undocumented, and in my testing does not appear to work with Auto Layout and thus rotation doesn't play nicely.
The library I linked above, APParallaxHeader, seems to work, but it's implementation is really confusing, and seems to be swizzling if I'm not wrong?
Is there a simple way to do this that I'm just completely overlooking?
I thought I'd throw out another idea that doesn't use a separate scroll view. I think this works a little better with the way it expands. So, in this attempt, I just add the image view as a subview of the main view, and placed it so 1/2 as much of the image view is above the top of the header (out of view) as below the header (initially hidden by the table rows). When pulling down the table, the view is moved down at half the rate of the pull down (by adjusting a constraint), so the top and the bottom of the image come into view together, then from there, I do the expansion by using a transform.
The project can be found here, http://jmp.sh/7PXzISZ
Hi heres my medium post on the subject:
https://medium.com/@jeremysh/creating-a-sticky-header-for-a-uitableview-40af71653b55#.hi79wgtsd
Just riffing here, but if the header's natural frame is
frame
, and you've got the table's scroll view delegate set, then the zoomed frame would be very similar to:Couple this with setting the contentMode on the image view to
UIViewContentModeScaleToFill
, and that should be a decent start.After giving this problem some more thought, I think the best way to duplicate that look is with a scrollview containing an image view that's behind (in the z-order sense) and extending below (in the y-direction sense) the top of a table view. In the test I did, I gave the table view a header (in IB) that was 100 points tall, and with a clear background color (the table also needs a clear background color). The scroll view and the table view were both pinned to the sides of the controller's main view, and to the top layout guide (the controller is embedded in a navigation controller, that was set to have its view not go under the top bar). The table view was also pinned to the bottom of the view, and the scroll view was given a fixed height of 200. I gave the scroll view an initial offset of 50 points, so that when you start to pull down on the table, the scroll view can scroll more content into view from the top, while also revealing more content at the bottom (the scroll view's offset is moving at 1/2 the rate of the table view's offset). Once the table view's offset reaches -50, I stop changing the scroll view's offset, and start zooming.
I've uploaded a copy of this project here, http://jmp.sh/LRKF0nM
Okay, here's an answer that has the benefit of getting built and tried out.
I found it too hard to manipulate the frame of the table's actual header view, so I added a subview to the table above the rows. In order for that view to show up as a regular table header, I gave the table a fixed sized, transparently colored header view.
The main idea is like what I answered above: using the table's content offset as the parameter for modifying the image view frame, and the imageView's content mode (corrected to UIViewContentModeScaleAspectFill) to provide the zooming effect as the frame changes.
Here's the whole view controller. This is built from a storyboard where the view controller is inside a navigation controller. It has nothing more than a table view filling its view, with the datasource and delegate set.