我该如何在Interface Builder中使用UIScrollView?

95

虽然我之前通过编程手动操作成功地使用UIScrollView,但我现在遇到了一些问题:尝试仅在Interface Builder中设置它的时候无法工作。

我有一个简单的“关于”页面在我的iPhone应用程序中。它包含一个UITextView,一些图标和链接到我的其他应用程序。我已经将所有这些视图添加到我的UIScrollView中,并将它们排列在一起使它们的总大小大于480。当我启动我的应用程序时,滚动视图仅显示适合屏幕的内容,并且没有任何滚动。

是否可以完全通过IB实现此功能,还是必须通过代码来操作contentSize

18个回答

130

你忘记设置UIScrollView的contentSize属性了。奇怪的是,你无法从Interface Builder中完成此操作。你需要从管理该滚动视图的视图控制器中进行设置。


43
哇,这有点让IB变得无意义了... 这个管用,谢谢。 - George Armhold
20
你可以创建一个UIScrollvView的子类,检查(0,0)位置是否只有一个子视图,然后根据该子视图自动设置contentSize大小。 - Stefan Arentz
1
这是我最近收到的最好的建议。我一直想不通为什么我的滚动视图不起作用,也没有在其他地方找到有关contentSize的信息。谢谢。 - Drew C
46
我试图弄清楚如何在Interface Builder中设置contentSize,并找到了这个讨论。至少对于我来说,在Xcode 4.5中,我可以使用“用户定义的运行时属性”进行设置,通过添加一个名为 contentSize 的条目,类型为 Size,并设置所需的值。 - nlogax
6
我仍然很困惑为什么iOS不会自动根据其子视图的尺寸来设置滚动视图的contentSize,至少作为默认行为。 - aroth
显示剩余4条评论

113
Boby_Wan的回答让我思考,我找到了以下用于在Interface Builder中配置UIScrollView内容大小的解决方案:
  1. 选中Storyboard场景中的UIScrollView
  2. 进入Identity inspector(身份信息检查器),创建一个新的User Defined Runtime Attribute(用户定义运行时属性) (点击+号按钮)
  3. 将属性Key Path(键路径)更改为contentSize
  4. 将属性Type(类型)更改为Size
  5. 现在将Value(值)设置为{所需内容宽度, 所需内容高度}

例如,将值设置为{320, 920}将允许用户在iPhone上向下滚动整个额外屏幕。

(我使用的是xcode 4.3.3,项目的为5.1)

当我第一次这样做时,我收到了以下错误:

  

非法配置:
         带有Xcode版本低于4.3的大小类型用户定义的运行时属性
         MainStoryboard.storyboard

如果您也遇到此错误,则很容易修复:选择Project Navigator(项目导航器)中的Storyboard,并打开File inspector(文件检查器)。 找到/展开Interface Builder Document(界面生成器文档)部分,其中有一个下拉列表可以选择Development(开发)。 确保将其设置为Xcode 4.3


8
太棒了!附言:我很惊讶这是苹果最好的所能做到的。我猜这说明即使是苹果员工也从未使用过他们自己的工具(界面构建器): )。 - Adam
太棒了,这在我的Xcode 4.4上刚刚起作用。但是现在我该如何在IB中放置滚动视图的不可“看到”的部分上的按钮? - Robert Atkins
1
我刚刚解决了这个问题 - 当指针仍在“屏幕”内时,必须释放拖动,否则它会回到起始位置。真是太麻烦了。 - Robert Atkins
我尝试用这种方式,但是我得到了一个错误:“此类不符合键值编码路径关键字的要求。” 你能帮助我看看哪里出了问题吗?请注意,我使用的是Xamarin-iOS-C#。 - SoftSan

25

使用Autolayout (iOS6+),您可以避免设置contentSize。请使用以下约束代替:

  1. 将滚动视图的顶部固定在其最顶部的子级上。
  2. 并将底部固定在其最底部的子级下面。

1
谢谢 - 在Xcode 5和iOS 7中设置contentSize无效。 - colincameron

18

您可以仅使用Interface Builder完成此操作,转到Identity Inspector(第三个检查器选项卡),并添加一个新的用户定义运行时属性,其值为

  • 键路径: contentSize
  • 类型: 大小
  • 值: {宽度,高度}

14

现在有一种方法可以在不离开Storyboard的情况下使UIScrollView滚动:

  1. 在Storyboard中选择UIScrollView,进入Size inspector并将Content Insets节的Bottom值(或其他需要更改的值)更改为内容区域的高度。
  2. 现在转到Identity inspector,创建一个新的User Defined Runtime Attribute(通过点击+按钮),并命名为contentSize。不管填什么TypeValue值(甚至可以保留其默认值)。

这将使UIScrollView正常工作,尽管我不知道为什么第二步是必要的(我是偶然发现的)。 :(


将底部值更改为什么? - zakdances
将其更改为内容区域的高度。它似乎有效,并覆盖您提供的用户定义的“contentSize”属性值。 - Reid Ellis
是的,Reid,你说得对:你应该将底部值更改为内容区域的高度。我已经编辑了我的原始帖子以反映这一点。谢谢! - RoberRM

4

我过去使用的一种方法是在界面构建器中将滚动视图拖出其包含视图,并将其实际大小设置为所需的contentSize。

关于界面构建器的一个不明显的特点是,您可以拥有未关联的视图,这些视图存储在nib中,但不是主要用于nib的视图的一部分。

在您想要滚动视图存在的视图中,放置一个简单的UIView,将其用作占位符。(这只是为了您可以在视觉上设计它的位置。如果您只是使用整个视图,则可以跳过此步骤并使用我在答案末尾提供的第二个代码片段)。

然后,您可以使用控件填充滚动视图,以视觉方式布局它。在您的视图控制器中为占位符和滚动视图分别设置属性,以便在运行时访问它们。

在 - (void)viewDidLoad 中运行时:

scrollView.contentSize = scrollView.frame.size;
scrollView.frame = placeholder.frame;
[placeholder.superview addSubView:scrollView];
[placeholder removeFromSuperview];

另一种选择(如果您没有使用占位符):
CGRect f = self.view.frame;
scrollView.contentSize = f.size;
f.origin.x = 0;
f.origin.y = 0;
scrollView.frame = f;
[self.view addSubView:scrollView];

最后,如果在接口构建器中“丢失”了滚动视图(有可能关闭它以使其从设计网格中消失),不要惊慌。只需在设计网格左侧的对象列表中单击它即可。


1
谢谢 - 这个很好用。还需要在YourViewController.h中声明占位符和滚动视图的IBOutlets,并在Interface Builder中连接它们。最后,xCode不支持第三行的点表示法,所以使用了普通的消息发送语法 - 然后一切都很好! - jiy
不用担心。发布代码片段时,总会存在一些人无法使用它们来理解概念,而是期望“精确”的代码在每种情况下都能正常工作,这是一个危险的行为。 - unsynchronized
这是我实际使用的方法。我甚至不需要调整这个程序的大小。我认为这就是预期的方式。这是唯一正确的答案。 - user4951
在外部绘制完成后,我只需将其移动到超级视图中。大功告成。 - user4951
我实际上开始使用设计一些场景外的视图来制作草稿和其他东西,在某些情况下,即使与此无关,这也会使生活变得更加轻松。感谢您的回答。 - Benjamin

4
在使用 Autolayout 的 Xcode 4.5 中,我的大小检查器中没有“内容插图(Content Insets)”部分。所以我在"用户定义的运行时属性(User Defined Runtime Attributes)"下添加了它, 然后它就正常工作了。
你需要添加的内容是 "keyPath == contentInset",其类型为"Rect" (UIEdgeInsets类型,与Rect有相同的输入) ,并且被定义为{top,left},{bottom,right}。contentSize仅定义滚动视图窗口的区域。contentInset定义可滚动区域。
我希望这能帮助处于同样境地的人。

对于UITextView,请使用"textContainerInset"关键路径。 - Dima Deplov

4
许多以上的答案都是误导性的或过时的。截至2017年(可能更早),界面生成器确实支持具有自动大小的内容的滚动视图。诀窍在于,XCode赋予了滚动视图和其中的内容之间的约束一个特殊的非标准含义。这些“内部”约束实际上不会像您本来期望的那样影响内容的大小。
这意味着您可以将您的滚动视图固定在主视图的底部,边距为零,并且将您的滚动视图的内容固定在滚动视图的底部,边距为零,但内容实际上不会因此而被拉伸。相反,内容将获得其自我确定的大小(更多信息请参见下文),这也将是可滚动区域在滚动视图内的大小。
可以这样想 - 将约束绑定到滚动视图中存在不对称性:从滚动视图到“外部”(父级)世界的约束通常确定滚动视图的大小和位置。但是,位于滚动视图“内部”的约束实际上是通过将其绑定到内容来设置滚动视图的可滚动区域的大小和位置。
这是完全不明显的,因为当您设置约束时,XCode将始终建议当前间距,并且您可能从未想过有意地更改内向和外向约束,以冲突的方式。但是您可以这样做,并且它们具有上述描述的含义:一个控制滚动视图布局,另一个控制可滚动内容区域的大小。
我偶然发现了这一点,然后看到它似乎有效,我找到了这篇文章,完全解释了这个问题,并引用了苹果文档的来源:

https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

最后一个关键信息,关于内容的自我确定大小:您可能会感到陷入困境,因为通常会将内容的大小调整为父视图的宽度,但在这种情况下,父视图是滚动视图,并且如上所述-约束不会影响您的内容大小。答案是要记住,您可以将项目约束到视图层次结构中未直接相邻的项目:例如,您可以将内容视图的宽度设置为主视图的宽度,而不是徒劳地尝试让滚动视图为您完成。


2

只需在滚动视图上删除autoLayout即可。然后代码就变得简单如下:

scrollviewName.contentSize = CGSizeMake(0, 650);

在.h文件中创建一个名为iboulet的属性,然后在.m文件中synthesize它。确保已启用滚动。

2

通过界面生成器设置UIScrollView并不直观。以下是我的设置清单:

  1. 选择UIViewController的XIB文件。在界面生成器的“Identity Inspector”中,将UIView更改为类类型UIScrollView

  2. 在“文件检查器”下,取消自动布局

  3. 在“属性检查器”下,将大小更改为Freeform。然后,您可以手动拉伸滚动视图,或者在“大小检查器”下指定自定义宽度和高度。

  4. 在“Identity Inspector”中,添加一个名为“contentSize”的新用户定义运行时属性,类型为“Size”,并将其更改为类似{320,1000}的值。您不能再以编程方式设置此选项,因此需要此步骤,以便ScrollView知道ScrollView的内容比窗口大。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接