4

I followed the tutorial about how to create a scrollView Page Control: http://www.iosdevnotes.com/2011/03/uiscrollview-paging/

This tutorial is really good and I implement well the code. Here my question:

I want to put a space between the my PageViews, but when it change the page it show the space between the views in the next page. The scroll must stop after the space when I change the page.

I changed the tutorial code here:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];

    #define space 20

    for (int i = 0; i < colors.count; i++) {
        CGRect frame;
        frame.origin.x = (self.scrollView.frame.size.width + space) * i;
        frame.origin.y = 0;
        frame.size = self.scrollView.frame.

        UIView *subview = [[UIView alloc] initWithFrame:frame];
        subview.backgroundColor = [colors objectAtIndex:i];
        [self.scrollView addSubview:subview];
        [subview release];
    }

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count+ space*(colors.count-1), self.scrollView.frame.size.height);
}
John Conde
  • 217,595
  • 99
  • 455
  • 496
rcmstark
  • 1,031
  • 1
  • 14
  • 18

2 Answers2

9

It sounds like you want a “gutter” between the pages, so that each page fills the scroll view and the gutter is only visible while the user is dragging the view. The built-in Photos app does this, for example.

Make your scroll view wider by space points. For example, if you want the scroll view to appear to be as wide as the screen (320 points), with a 20 point margin between items, then make the scroll view 340 points wide, with the extra 20 points hanging off the right edge of the screen.

- (void)viewDidLoad {
    [super viewDidLoad];

    NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];

    #define kGutterWidth 20

    UIScrollView *scrollView = self.scrollView;
    CGRect scrollViewFrame = scrollView.frame;
    scrollViewFrame.size.width += kGutterWidth;
    scrollView.frame = scrollViewFrame;

    CGSize scrollViewSize = scrollView.bounds.size;

    for (int i = 0; i < colors.count; i++) {
        CGRect frame = CGRectMake(scrollViewSize.width * i, 0,
            scrollViewSize.width - kGutterWidth, scrollViewSize.height);
        UIView *subview = [[UIView alloc] initWithFrame:frame];
        subview.backgroundColor = [colors objectAtIndex:i];
        [scrollView addSubview:subview];
        [subview release];
    }

    scrollView.contentSize = CGSizeMake(
        colors.count * scrollViewSize.width,
        scrollViewSize.height);
}
danh
  • 62,181
  • 10
  • 95
  • 136
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Not sure I get the idea, @rob. Won't the 20px be visible on the right hand side of each subview? p.s. Thanks for the many, many great answers you've given on SO. I've relied on your smartness many times. – danh Sep 11 '12 at 03:21
  • @danh The 20 points will hang off the right edge of the screen, invisible. Note that my example code widens the scroll view by the gutter width, but then subtracts that gutter width from the width of each page view. Thus if the scroll view was originally as wide as the screen, each page is exactly the width of the screen, and the gutter is only visible while the user is scrolling. – rob mayoff Sep 11 '12 at 03:24
  • Oh. I see. But that won't that make the gutter show up on the left side of the last page? (ps - I think you want scrollViewSize to be a CGSize, not CGRect). – danh Sep 11 '12 at 03:34
  • Hmm. You might have to not subtract `kGutterWidth` from the `contentSize` width, but I'm not sure. I don't feel like trying it out right now. – rob mayoff Sep 11 '12 at 03:35
  • Just tried it out: 1) I was right about the last page. 2) you are right that not subtracting kGutterWidth from content size fixes that. 3) My approach worked fine, too, answering a slightly different requirement. Not sure what the questioner wanted. Edited yours to work. – danh Sep 11 '12 at 03:43
2

I've been down this road before, and I would advise laying out the scroll view as the tutorial code recommends, with no space between the subviews.

Instead, give each subview another subview whose frame is inset from it's parent...

CGRect scrollViewFrame = self.scrollView.frame;

for (int i=0; i<colors.count; i++) {
    CGRect frame = CGRectMake(scrollViewFrame.size.width * i, 0, scrollViewFrame.size.width, scrollViewFrame.size.height);

    // this will be our framing view, full size with no gaps
    UIView *subview = [[UIView alloc] initWithFrame:frame];
    subview.backgroundColor = [UIColor whiteColor];

    // here's the trick - use CGRectInset on the framing view's bounds
    UIView *colorView = [[UIView alloc] initWithFrame:CGRectInset(subview.bounds, 10, 10)];
    colorView.backgroundColor = [colors objectAtIndex:i];

    [subview addSubview:colorView];
    [self.scrollView addSubview:subview];

    // aren't you using ARC?  your tutorial is probably older than ARC
    // would strongly suggest converting to ARC
    [subview release];
    [colorView release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count, self.scrollView.frame.size.height);

The benefit of this approach is that the math for the top level subview layout remains a simple multiple of the width. The only place you'll refer to that inset constant is on the CGRectInset where it belongs.

danh
  • 62,181
  • 10
  • 95
  • 136