6
votes

Description

If you use the Spotify app on iOS or Android (I am developing on iOS), you'll notice that if you select a playlist, and drag the UITableView with your songs up, the following happens:

The table doesn't scroll, it just moves up at the same speed it would scroll, and the images above it move slower than the table, creating a parallax scrolling effect. Once the tableview reaches the top of the view, however, it behaves like a normal scrolling tableview.

I've tried to achieve this effect a few different ways, which didn't work for me.

Here is a video of this effect: https://www.dropbox.com/s/n7npk4lrzmag0sn/IMG_9331.MOV

What I tried

I wanted the UITableView and the UIScrollView above it, to move upwards when the user scrolled either one, so I used

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

and based on the direction of the scroll, I changed the frame position of the tableview and the UIScrollView above it.

The problem with this method is that the tableview bounces, which ruins the effect.

To get rid of bouncing, I tried the following:

_userTableView.bounces = NO;

However, now because the tableview wouldn't scroll, scrollViewDidScroll is never called.

The other thing I tried was subclassing the UITableView, and overriding the

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

hitTest method to detect a scroll gesture on the tableview, the problems with this are:

  • Only 1 CGPoint is passed -- it's impossible to know if the UITableView was touched, or scrolled.
  • Since scrolling is disabled, I can't use self.decelerating to check if the tableview was just scrolled -- the tableview will never be decelerating
  • Making the table decelerate as it moves up the view, and continue scrolling with the same momentum after its reached the top will be very challenging; In the Spotify app, a user can drag the table with a speed high enough to make the table view move to the top of the view AND continue scrolling, all in one motion.

The tableview should grow in size to accommodate more cells added to the view (without scrolling), as it moves up the view, or it should start out with the same size as the view. After it reaches the top it should begin scrolling like a normal tableview -- with the same momentum it has after the upward movement.

Any suggestions on how I can solve this?

Thank you very much.

1
Here is a project (for UICollectionView), but it's exactly the effect you want I think: github.com/jamztang/CSStickyHeaderFlowLayoutLapinou

1 Answers

2
votes

For the effect you have shown, I think a tableHeaderView with the parallax content as a subview will suffice.

In -scrollViewDidScroll: (or KVO for contentOffset), you set the center of the parallax subview to the center of the visible bounds of the tableHeaderView. You can also adjust how much the content "sticks" to the center by multiplying a factor.

CGRect tableViewHeaderVisibleBounds = tableViewHeader.bounds;
tableViewHeaderVisibleBounds.origin.y = MAX(0, MIN(CGRectGetHeight(tableViewHeader.bounds), tableView.contentOffset.y));
tableViewHeaderVisibleBounds.size.height -= tableViewHeaderVisibleBounds.origin.y;

CGFloat factor = 1.8f; // less than 0.5:stick to top // greater than 0.5:stick to bottom 
parallaxContentView.center = (CGPoint){
    .x = parallaxContentView.center.x,
    .y = (CGRectGetMinY(tableViewHeaderVisibleBounds)
         + (CGRectGetHeight(tableViewHeaderVisibleBounds) * factor))
};

I coded this inside my head so just make necessary adjustments, but I hope you get the basic idea.