使用pagingEnabled在UIScrollView中的页面之间的应用程序之间的差距

时间:2009-05-11 18:22:05

标签: iphone cocoa-touch uiscrollview

分页模式下的UIScrollView假设页面彼此相邻,没有间隙。但是,如果您在“照片”应用中打开照片并在照片中滑动,则可以看到页面之间存在一些差距。我也想要这些差距。

我正在寻找现有的解决方案,或者除了我在下面解释的那个之外,还有一些关于实现页面间隙的奇怪想法。或者也许我有一些明显的简单方法?

要明确:我希望在滚动时只能看到间隙,所以我不能简单地插入页面内容。


我的计划是尝试从scrollViewDidScroll回调内移动页面内容,以便(假设您向右滚动)最初目标页面略微偏移到其页面边界的右侧,并且到达目标页面的时间它返回到正确的位置,源页面稍微偏移到其边界的左侧。 (或者也许不是连续不断地移动东西,我会更好地改变偏移量,比如恰好在页面之间。)

我是ScrollingMadness article+example的作者,我一直在这里引用一些人。我已经实现了编程缩放,并且使用照片间缩放和滚动工作以及照片间分页。所以我知道如何使用UIScrollView,我正在寻找高级的东西。

请不要指向TTScrollView。我自己已经指出了很多人,但我认为它与原生的UIScrollView行为相距太远,并且不想在我的项目中使用它。

8 个答案:

答案 0 :(得分:27)

  

请注意,这个答案很老了。基本概念仍然有效   你不应该在iOS7和8中硬编码视图大小。即使你忽略了   建议,你不应该使用480或330。

您是否尝试将UIScrollView的框架设置为略大于屏幕(假设您要全屏显示图像,然后将您的子视图排列在同样略大于屏幕的边界上。

#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];

道歉,如果这不能编译,我在横向应用程序中测试它并手动编辑回肖像。我相信你明白了。它依赖于超视图剪辑,对于全屏视图总是如此。

答案 1 :(得分:22)

所以我没有足够的“代表”对上面的答案发表评论。答案是正确的,但有一个大问题需要注意:

如果你在一个属于UINavigationController的viewController中使用UIScrollView,导航控制器会调整你的scrollView框架的大小。

也就是说,您有一个使用UINavigationController在不同视图之间切换的应用程序。您推送一个具有scrollView的viewController,并在viewController的-init方法中创建此scrollView。您为其指定了一个(0,0,340,480)的帧。

现在,转到viewController的-viewDidAppear方法,获取您创建的scrollView的框架。您会发现宽度已减少到320像素。因此,分页将无法正常工作。你会期望scrollView移动340像素,但它会移动320。

UINavigationController对于搞乱子视图有点臭名昭着。它移动它们并调整它们以适应导航栏。简而言之,它不是一个团队合作者 - 特别是在这种情况下。如果您需要精确控制视图的大小和位置,Web上的其他位置建议您不要使用UINavigationController。他们建议您基于UINavigationBar创建自己的navigationController类。

这是一项很大的工作。幸运的是,有一个更简单的解决方案:在viewController的-viewDidAppear方法中设置scrollView的框架。此时,UINavigationController完成了框架的混乱,因此您可以将其重置为应该的状态,并且scrollView将正常运行。

这与OS 3.0相关。我没有测试3.1或2.2.1。我还向Apple提交了一个错误报告,建议他们使用BOOL修改UINavigationController,例如“-shouldAutoarrangeSubviews”,以便我们可以让该类保持其粗略的关闭子视图。

在此之前,上面的修复将为您提供UINavigationController中分页UIScrollView的空白。

答案 2 :(得分:7)

Apple已向iphone开发者计划的所有成员发布了2010 WWDC会话视频。讨论的主题之一是他们如何创建照片应用程序!他们逐步构建一个非常相似的应用程序,并使所有代码免费提供。

它也不使用私人api。这是示例代码下载的链接。您可能需要登录才能获得访问权限。

http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645

并且,这是iTunes WWDC页面的链接:

http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj

答案 3 :(得分:4)

这样做的方法就像你说的那样,是一些事情的组合。

如果您希望图片之间的间隔为20px,则需要:

首先,将滚动视图的总宽度扩展20px,然后向左移动10px。

其次,当您布置图像的xLoc时,为每个图像添加20px,使它们间隔20px。 第三,将图像的初始xLoc设置为10px而不是0px。

第四,确保设置滚动视图的内容大小,为每个图像添加20px。所以如果你有kNumImages图像,每个都是kScrollObjWidth,那你就这样:

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

之后它应该有效!

答案 4 :(得分:0)

这只是一种预感,所以如果完全错误就道歉,但是有可能将contentSize设置为略宽于屏幕宽度。

然后在视图中将正确的信息呈现到屏幕宽度,UIScrollView负责其余部分?

答案 5 :(得分:0)

也许您想尝试UIScrollView的contentInset属性?

myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);

答案 6 :(得分:0)

我只是觉得我在这里为后人添加了我最终选择的解决方案。很长一段时间以来,我一直在使用Bryan在-viewDidAppear中调整框架的解决方案,这一点非常出色。但是,由于iOS引入了多任务处理,我遇到了一个问题,当应用程序从后台恢复时,滚动视图框会发生变化。在这种情况下,-viewDidAppear没有被调用,我找不到在适当的时候调用以转换更改的委托方法。所以我决定让我的滚动视图成为我的View Controller视图的子视图,这似乎解决了这个问题。这样做的好处是不需要使用-viewDidAppear来更改框架 - 您可以在创建滚动视图后立即执行此操作。我的问题here有详细信息,但我也会在这里发布:

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];

答案 7 :(得分:0)

为避免弄乱UIScrollView的框架,您可以继承UIScrollView并覆盖layoutSubviews,以便为每个页面应用偏移量。

这个想法基于以下观察:

  1. 当zoomScale!= 1时,当它在左/右边缘时偏移为零
  2. 当zoomScale == 1时,当它位于可见的矩形中心时,偏移量为零
  3. 然后导出以下代码:

    - (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);
        }
    }