6

I am creating an iPhone app with a large, 360 degree, panorama image. The panorama is a CATiledLayer in a UIScrollView.

I am attempting to implement infinite scrolling on the image (horizontal only). I have done this by subclassing UIScrollView and implementing setContentOffset: and setContentOffset:animated: and this works perfectly when the user is dragging the scrollview. However, when the user has lifted their finger and the scrollview is decelerating, changing the contentOffset causes the deceleration to stop instantly.

- (void)setContentOffset:(CGPoint)contentOffset 
{    
    CGPoint tempContentOffset = contentOffset;

    if ((int)tempContentOffset.x >= 5114)
    {
        tempContentOffset = CGPointMake(1, tempContentOffset.y);
    }
    else if ((int)tempContentOffset.x <= 0)
    {
        tempContentOffset = CGPointMake(5113, tempContentOffset.y);
    }

    [super setContentOffset:tempContentOffset];    
}

Is there any way to change the contentOffset without affecting deceleration?

It was suggested here that overriding setContentOffset: (not setContentOffset:animated:) fixes this issue, but I can't seem to get it working.

I have also tried scrollRectToVisible:animated: with no success.

Any ideas on how to fix this problem would be greatly appreciated. Thanks!

EDIT:

Code for scrollViewDidScroll:

-(void)scrollViewDidScroll:(PanoramaScrollView *)scrollView
{
    [panoramaScrollView setContentOffset:panoramaScrollView.contentOffset];
}   

I also tried this:

-(void)scrollViewDidScroll:(PanoramaScrollView *)scrollView
{
    CGPoint tempContentOffset = panoramaScrollView.contentOffset;

    if ((int)tempContentOffset.x >= 5114)
    {
        panoramaScrollView.contentOffset = CGPointMake(1, panoramaScrollView.contentOffset.y);
    }
    else if ((int)tempContentOffset.x == 0)
    {
        panoramaScrollView.contentOffset = CGPointMake(5113, panoramaScrollView.contentOffset.y);
    }
}
Community
  • 1
  • 1
Steph Sharp
  • 11,462
  • 5
  • 44
  • 81

4 Answers4

4

Instead of

[scrollView setContentOffset:tempContentOffset];

use

scrollView.contentOffset = tempContentOffset;
david72
  • 7,151
  • 3
  • 37
  • 59
2

I resolved the issue with a workaround. I created a panorama image with 3 full widths of the panorama (doesnt affect performance too much because I'm using CATiledLayer), and set the decelerationRate property to UIScrollViewDecelerationFast. Therefore, the user is unable to scroll too far before the deceleration stops, and if the deceleration stops in either the left or right panorama image, the content offset is then changed back to the middle image. This has the appearance of infinite scrolling, and it's the best solution I could come up with.

Steph Sharp
  • 11,462
  • 5
  • 44
  • 81
  • To avoid the need for `UIScrollViewDecelerationFast`, you could make the `contentSize` very large, start off with your triple-width content view and viewpoint in the middle, and arrange for that content view to be repositioned while scrolling; then, when deceleration stops, put everything back in the middle again. – hatfinch Nov 06 '13 at 10:37
  • @hatfinch Thanks for your comment. That's pretty much what I ended up doing, but I'm not 100% sure what you meant by "arrange for that content view to be repositioned while scrolling". Can you explain how this would work? – Steph Sharp Nov 19 '13 at 03:37
  • It would work just like the method you described, except instead of crippling the deceleration to ensure that the user can't scroll off the triple-width panorama, you're moving the panorama. So for a "content view" ABC, you have xxxABCxxx in the scrollview (x is just blank space), and when the user scrolls e.g. to the left, after they've scrolled one image-width, you move the content view so that you have xxABCxxxx. Except that you do it with so many 'x's that they would have to be very deliberate about trying to reach the edge. Does that make sense? – hatfinch Nov 19 '13 at 16:22
1

I recently was doing the same infinite scrolling and accidentally found the solution:

Just set bounces=YES, alwaysBounceHorizontal=YES or/and alwaysBounceVertical=YES (depends on direction you scrolling to).

That's it, this works for me. :)

krafter
  • 1,425
  • 1
  • 15
  • 28
0

i would try to use the UIScrollViewDelegate protocol method:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;

it's called when user scroll (even when it's decelerating)

and inside it i would change the contentoffset

meronix
  • 6,175
  • 1
  • 23
  • 36
  • The scrollViewDidScroll method is where I am calling the setContentOffset method shown above. I also tried directly setting the contentOffset in scrollViewDidScroll, but no luck. Whenever the content offset is set, the deceleration instantly stops. The log output below shows the content offset change, and then scrollViewDidEndDecelerating is triggered. `(62.000000 0.000000) (22.000000 0.000000) (0.000000 0.000000) (5113.000000 0.000000) scrollViewDidEndDecelerating` – Steph Sharp May 04 '12 at 06:19