Photos app-like gap between pages in UIScrollView with pagingEnabled

后端 未结 8 1140
北恋
北恋 2020-12-04 08:52

UIScrollView in paging mode assumes the pages are located right next to each other, with no gap. However if you open a photo in the Photos app and swipe through photos, you

相关标签:
8条回答
  • 2020-12-04 09:08

    Maybe you want to try UIScrollView's contentInset property?

    myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);
    
    0 讨论(0)
  • 2020-12-04 09:17

    This is just a hunch, so apologies if completely wrong, but is it possible that the contentSize is just set to slightly wider than the screen width.

    The correct information is then rendered within the view to the screen width and UIScrollView takes care of the rest ?

    0 讨论(0)
  • 2020-12-04 09:21

    To avoid messing with UIScrollView's frame, you could subclass UIScrollView and override layoutSubviews to apply an offset to each page.

    The idea is based on the following observations:

    1. When zoomScale !=1, the offset is zero when it is at the left / right edge
    2. When zoomScale ==1, the offset is zero when it is at the visible rect centre

    Then the following code is derived:

    - (void) layoutSubviews
    {
        [super layoutSubviews];
    
        // Find a reference point to calculate the offset:
        CGRect bounds = self.bounds;
        CGFloat pageGap = 8.f;
        CGSize pageSize = bounds.size;
        CGFloat pageWidth = pageSize.width;
        CGFloat halfPageWidth = pageWidth / 2.f;
        CGFloat scale = self.zoomScale;
        CGRect visibleRect = CGRectMake(bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale);
        CGFloat totalWidth = [self contentSize].width / scale;
        CGFloat scrollWidth = totalWidth - visibleRect.size.width;
        CGFloat scrollX = CGRectGetMidX(visibleRect) - visibleRect.size.width / 2.f;
        CGFloat scrollPercentage = scrollX / scrollWidth;
        CGFloat referencePoint = (totalWidth - pageWidth) * scrollPercentage + halfPageWidth;
    
        // (use your own way to get all visible pages, each page is assumed to be inside a common container)
        NSArray * visiblePages = [self visiblePages];
    
        // Layout each visible page:
        for (UIView * view in visiblePages)
        {
            NSInteger pageIndex = [self pageIndexForView:view]; // (use your own way to get the page index)
    
            // make a gap between pages
            CGFloat actualPageCenter = pageWidth * pageIndex + halfPageWidth;
            CGFloat distanceFromRefPoint = actualPageCenter - referencePoint;
            CGFloat numOfPageFromRefPoint = distanceFromRefPoint / pageWidth;
            CGFloat offset = numOfPageFromRefPoint * pageGap;
            CGFloat pageLeft = actualPageCenter - halfPageWidth + offset;
    
            view.frame = CGRectMake(pageLeft, 0.f, pageSize.width, pageSize.height);
        }
    }
    
    0 讨论(0)
  • 2020-12-04 09:22

    I just thought I'd add here for posterity the solution I ended up going with. For a long time I've been using Bryan's solution of adjusting the frame in -viewDidAppear, and this has worked brilliantly. However since iOS introduced multitasking I've been running into a problem where the scroll view frame gets changed when the app resumes from the background. In this case, -viewDidAppear was not being called and I couldn't find a delegate method that would be called at the right time to reverse the change. So I decided to make my scroll view a subview of my View Controller's view, and this seemed to fix the problem. This also has the advantage of not needing to use -viewDidAppear to change the frame - you can do it right after you create the scroll view. My question here has the details, but I'll post them here as well:

    CGRect frame = CGRectMake(0, 0, 320, 460);
    scrollView = [[UIScrollView alloc] initWithFrame:frame];
    
    // I do some things with frame here
    
    CGRect f = scrollView.frame;
    f.size.width += PADDING; // PADDING is defined as 20 elsewhere
    scrollView.frame = f;
    
    [self.view addSubview:scrollView];
    
    0 讨论(0)
  • 2020-12-04 09:29

    The way to do this is like you said, a combination of a few things.

    If you want a gap of 20px between your images, you need to:

    First, expand your scroll view's total width by 20px and move it left by 10px.

    Second, when you lay out the xLoc of your images, add 20px for each image so they're spaced 20px apart. Third, set the initial xLoc of your images to 10px instead of 0px.

    Fourth, make sure you set the content size of your scroll view to add 20px for each image. So if you have kNumImages images and each is kScrollObjWidth, then you go like this:

    [scrollView setContentSize:CGSizeMake((kNumImages * (kScrollObjWidth+20)),  kScrollObjHeight)];
    

    It should work after that!

    0 讨论(0)
  • 2020-12-04 09:31

    Note that this answer is quite old. The basic concept still works but you should not be hard coding view sizes in iOS7 and 8. Even if you ignore that advice, you should not use 480 or 330.

    Have you tried making the frame of the UIScrollView slightly larger than the screen (assuming that you want to display your images fullscreen and then arranging your subviews on the same slightly-larger-than-the-screen boundaries.

    #define kViewFrameWidth 330; // i.e. more than 320
    
    CGRect scrollFrame;
    scrollFrame.origin.x = 0;
    scrollFrame.origin.y = 0; 
    scrollFrame.size.width = kViewFrameWidth;
    scrollFrame.size.height = 480;
    
    UIScrollView* myScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
    myScrollView.bounces = YES;
    myScrollView.pagingEnabled = YES;
    myScrollView.backgroundColor = [UIColor redColor];
    
    UIImage* leftImage = [UIImage imageNamed:@"ScrollTestImageL.png"];
    UIImageView* leftView = [[UIImageView alloc] initWithImage:leftImage];
    leftView.backgroundColor = [UIColor whiteColor];
    leftView.frame = CGRectMake(0,0,320,480);
    
    UIImage* rightImage = [UIImage imageNamed:@"ScrollTestImageR.png"];
    UIImageView* rightView = [[UIImageView alloc] initWithImage:rightImage];
    rightView.backgroundColor = [UIColor blackColor];
    rightView.frame = CGRectMake(kViewFrameWidth * 2,0,320,480);
    
    UIImage* centerImage = [UIImage imageNamed:@"ScrollTestImageC.png"];
    UIImageView* centerView = [[UIImageView alloc] initWithImage:centerImage];
    centerView.backgroundColor = [UIColor grayColor];
    centerView.frame = CGRectMake(kViewFrameWidth,0,320,480);
    
    [myScrollView addSubview:leftView];
    [myScrollView addSubview:rightView];
    [myScrollView addSubview:centerView];
    
    [myScrollView setContentSize:CGSizeMake(kViewFrameWidth * 3, 480)];
    [myScrollView setContentOffset:CGPointMake(kViewFrameWidth, 0)];
    
    [leftView release];
    [rightView release];
    [centerView release];
    

    Apologies if this doesn't compile, I tested it in a landscape app and hand edited it back to portrait. I'm sure you get the idea though. It relies on the superview clipping which for a full screen view will always be the case.

    0 讨论(0)
提交回复
热议问题