Give us a call 888-856-2664
Get a Quote Today

Things a Chameleon Would Say

Web design

Objective C – Multiple Pages in a UIScrollView
By: Jacob Haskins 06/29/2011

Enabling paging in a UIScrollView will allow you to have a nice ‘snap-to’ effect. It’s exactly what you see when using the Photo app. I recently wanted to utilize this effect while displaying multiple pages on the screen but ran into a few issues. Problems and solutions below. Also, you can picture any ‘pages’ that I make reference to will just display an image as content.

Problem 1 – Swipe Not Detected

Consider this: You have a page in the center of the screen. To the left you see half of another page and to the right you see half of another page. Setting this up should be easy. Uncheck ‘Clip Subviews’, check ‘Paging Enabled’ and set the frame to be the size of each page. Great, it all works! Except you can only swipe if touch begins in the center page. So if I start my swiping in one of the pages that is partly showing on the right or left then nothing would happen. While some would accept this as a mild annoyance and move on, not the perfectionists professionals at Accella!

Solution 1 – Swipe Detected

The solution to this problem involves placing the UIScrollView inside a UIView and overriding the hitTest method of the UIView to pass along the touch to the child UIScrollView. So start by subclassing the UIView, add a reference to the UIScrollView inside UIView and finally add the following code to your UIView subclass:

- (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event {   if ([self pointInside:point withEvent:event]) {     return scrollView;   }   return nil; }

Problem 2 – I want more than three pages on the screen

I actually needed to display 7 small images on the screen at one time. It was a horizontal bar that was the full width of the screen and held about 50 pages. Things were working in that I could swipe anywhere in that bar and I did get my nice ‘snap-to’ effect from the paging. However, things were a little too rigid. I got the ‘snap-to’ effect but had no momentum with my swipe. Swiping would instantly stop at the nearest page when I lifted my finger.

Solution 2 – I guess I don’t want paging after all

I determined that paging isn’t really what I was trying to achieve. What I really wanted was to have normal swiping, but have the UIScrollView ‘snap-to’ the center of the nearest page once it stopped. So it was a combination of ‘snap-to’ and momentum. To achieve this I entirely removed my previous solution and turned off paging. At this point I had just a free scrolling UIScrollView.

What I then did was monitored the UIScrollView to determine when it started to slow down. If it slowed down to a certain point then I knew it was about to stop. At that point we just set the content offset and set animation to ‘YES’. This provides a seamless animation for the whole process. I also need to have the ‘snap-to’ effect when just dragging, but not necessarily swiping.

#pragma mark - UIScrollViewDelegate // Note the width of my pages is set to 52px - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {     monitorVelocity = decelerate;     currentTime = [[NSDate date] timeIntervalSince1970];     prevTime = [[NSDate date] timeIntervalSince1970];     currentPosition = pickerScrollView.contentOffset.x;     prevPosition = pickerScrollView.contentOffset.x;         if(!decelerate) {         CGFloat offset = round(currentPosition/52)*52;         // only snap-to if offset is within content bounds to prevent interference with the scrollviews bounce property         if(currentPosition > 0 && offset < pickerScrollView.contentSize.width && currentPosition < pickerScrollView.contentSize.width-52) {             [pickerScrollView setContentOffset:CGPointMake(offset,0) animated:YES];         }     } } - (void)scrollViewDidScroll:(UIScrollView *)scrollView {     if (monitorVelocity) {         currentTime = [[NSDate date] timeIntervalSince1970];         currentPosition = pickerScrollView.contentOffset.x;         float velocity = abs((currentPosition - prevPosition) / (currentTime - prevTime));         prevTime = currentTime;         prevPosition = currentPosition;                 if (velocity  10) {             monitorVelocity = NO;             CGFloat offset = round(currentPosition/52)*52;             // only snap-to if offset is within content bounds to prevent interference with the scrollviews bounce property             if(currentPosition > 0 && offset < pickerScrollView.contentSize.width && currentPosition < pickerScrollView.contentSize.width-52) {                 [pickerScrollView setContentOffset:CGPointMake(offset,0) animated:YES];             }         }     } }

 

One Response to “Objective C – Multiple Pages in a UIScrollView”

  1. ash February 21, 2012

    Thx, that got me started. One thing I would add is scrollViewDidEndDecelerating and a call to snap the position. It is possible for the velocity to drop from something like like 14 to 0, so the call to snap in scrollViewDidScroll might never be called. Alternatively, you could completely eliminate the if(velocity < 10) in scrollViewDidScroll completely and have it handled in scrollViewDidEndDecelerating.

    Also, because setContentOffset:animated uses a constant velocity, the snap is more prominent than the animation used in the picker control which appears to adjust the speed of the snap based on the distance.

    Cheers,
    Ash

Leave a Reply




Have a Question? Need a Quote?

Drop us a line or give us a call at 888-856-2664

Your Name (required)
Your Email (required)
Phone (required)
Your Message

What Our Clients Are Saying

John,
Can I just tell you how impressed I am with your team?! This whole process has been so great and working with you guys has made it SOOOO much easier! Thank you for all your hard work and for convincing us to choose Accella.

SO THRILLED!!

Alycia White
Kubota

Recent Posts

Getting Arrested Can Help Your Business

While generally coming face to face with the law is generally not good for...

Drupal 6 with UberCart / UberPOS - A Love-Hate Relationship?

As most techies and programmers have heard, the Drupal CMS is an extremely...