我如何使用Autolayout在我的UIScrollview上设置约束?

我已经花了两天的时间尝试了混合和纯粹的Autolayout方法的各种解决scheme,以实现自动布局之前的一个微不足道的scrollview设置,现在是正式的 – 我一定是太愚蠢了。 我主要是在Storyboard中设置它(呃,就是这样)。

所以这是我的求助。

Viewtree:

UIView -UIView -UIView ..-UIScrollview ...-UIButton ...-UIButton ...-UIButton 

button应该水平滚动(从左到右,反之亦然)。 有人可以让我知道如何设置约束,以实现这个使用纯粹的Autolayout?

我尝试了混合的方法,像这样:

 UIView - UIView - UIView ..-UIScrollview ...-UIView (contentview) ....-UIButton ....-UIButton ....-UIButton 

…并按照Apple的技术说明为contentviewtranslatesAutoresizingMaskIntoConstraints设置设置固定的宽度和高度约束。 button和滚动视图使用约束设置。 这得到滚动视图滚动(耶),但唉,它滚动太多了! 据我所知,滚动宽度是从我设置内容视图??? ??? ???

我也尝试了纯粹的自动布局方法,无论是contentview还是没有。 所有的意见都translatesAutoresizingMaskIntoConstraints=NO self.view translatesAutoresizingMaskIntoConstraints=NO ,除了self.view 。 button具有固定的宽度/高度约束,并固定在滚动视图的所有四个边上。 什么都不滚动。

所以我很困惑为什么我不能正确地工作。 任何帮助非常感谢,如果您需要任何其他信息,请问!

更新解决scheme的屏幕截图 – buttonZ约束:

在这里输入图像描述

编辑@杰米福雷斯特因此,解决scheme原来是最后一个button错误的尾随约束。 我所设定的价值是6441,而不是6441。 棘手的是,当在故事板中设置值时,Pin工具栏中有两个选项:

在这里输入图像描述

当前canvas值是负值(导致不滚动),下面的选项是正值(激活滚动)。 这意味着我不愚蠢,但至less我是半盲。 虽然,我的辩护,是不是有点令人不安,XCode不显示错误的“不正确的”设置?

再次编辑现在,这很有趣…将尾随值从-6441(不滚动)更改为6441启用滚动。 但是我的老朋友“内容太多”又回来了,导致内容的大小是原来的两倍! 获得正确的内容滚动的解决scheme是将尾部约束设置为零! 当在Storyboard中工作时,这并不明显,但是看@Infinity James的代码,应该是这样。

你很难看到你的限制的确切值和设置,所以我不能确定你的屏幕截图是哪里出了问题。

代替你的设置中的错误的解释,我已经创build了一个基本的示例项目 ,它具有非常相似的视图层次结构和约束设置。 示例项目中的水平滚动按预期工作,该示例项目使用Apple在技术说明中描述的“Pure AutoLayout”方法。

我也有很多麻烦,最初让自动布局与UIScrollView工作。 让它工作的关键是确保所有的滚动视图中的项目都有约束,最终链接到滚动视图的所有方面,并有助于AutoLayout系统能够确定一个contentSize滚动视图将比它的框架更大。 看起来你正在试图在你的代码中这样做,但也许你有一些多余的限制,使contentSize太小。

同样值得注意的是,正如其他人所提到的,使用AutoLayout和UIScrollview,你不再明确地设置contentSize。 AutoLayout系统根据您的约束计算contentSize。

我还发现这本电子书章节是非常有用的,使我明白这是如何工作的。 希望这一切都有帮助。

大声笑欢迎愚蠢俱乐部。 我是创始人之一。 :d

对于垂直滚动 :我可以得到它的唯一方法(iOS 8,Xcode 6和纯自动布局)是添加以下约束到我的滚动视图(所有相关的超视图):

  • 相等的宽度
  • 平等的高度
  • 中心Yalignment
  • 中心Xalignment

我的结构:

  UIView - ScrollView - Subview - Subview - Subview - Subview - ... 

这是最后的结果:

演示

这是设置:

建立 全屏

这是这个项目 。

希望这可以帮助人们在上午5点睡觉。 :d

简单的自包含示例

由于问题得票多,回答数量less,人们在这里找不到一个可以理解和迅速解决的办法。 让我试着添加一个。 这个项目是一个独立的例子完全在Interface Builder中完成。 你应该可以在10分钟或更短的时间内完成。 然后,您可以将您学到的概念应用到您自己的项目中。

在这里输入图像描述

原来的问题是关于滚动button的问题。 在这里,我只是使用UIView s,但他们可以代表任何你喜欢的看法。 我还select了横向滚动,因为这个格式的故事板截图更加紧凑。 但是,垂直滚动的原则是一样的。

关键概念

  • UIScrollView应该只使用一个子视图。 这是一个'UIView'作为内容视图来保存你想要滚动的一切。
  • 使内容视图和滚动视图的父级具有相同的水平滚动高度。 (等宽垂直滚动)
  • 确保所有的可滚动内容都有一个设定的宽度,并固定在所有的侧面。

开始一个新的项目

它可以只是一个单一的视图应用程序。

故事板

在这个例子中,我们将制作一个水平滚动视图。 select视图控制器,然后在大小检查器中select自由forms。 使宽度为1,000 ,高度为300 。 这只是给我们在故事板上的空间来添加将滚动的内容。

在这里输入图像描述

添加滚动视图

添加一个UIScrollView并将所有四边固定到视图控制器的根视图。

在这里输入图像描述

添加内容视图

UIView作为子视图添加到滚动视图。 这是关键。 不要尝试添加大量的子视图到滚动视图。 只需添加一个UIView 。 这将是您想要滚动的其他视图的内容视图。 将内容视图固定在所有四面的滚动视图中。

在这里输入图像描述

平等的高度

现在在“文档大纲”中, 命令单击内容视图和滚动视图的父视图 ,以select它们。 然后设置高度相等( 控制从内容视图拖动到滚动视图)。 这也是关键。 因为我们是水平滚动的,滚动视图的内容视图将不知道应该有多高,除非我们这样设置。

在这里输入图像描述

注意:

  • 如果我们使内容垂直滚动,那么我们将内容视图的宽度设置为等于滚动视图的父宽度。

添加内容

添加三个UIView并给他们所有的约束。 我用了8点利润的一切。

在这里输入图像描述

约束:

  • 绿色视图:固定顶部,左侧和底部边缘。 使宽度400。
  • 红色视图:固定顶部,左侧和底部边缘。 使宽度300。
  • 紫色视图:钉住所有四个边缘。 无论剩余空间是多less(在这种情况下为268)。

设置宽度约束也是关键,因此滚动视图知道其内容视图将有多宽。

成品

就这样。 你现在可以运行你的项目。 它的行为应该像这个答案顶部的滚动图像。

对于垂直滚动,只需交换本例中的所有宽度和高度方向(testing和工作)。

进一步研究

  • iOS:如何使AutoLayout在ScrollView上工作
  • 如何在Interface Builder中使用Auto LayoutconfigurationUIScrollView
  • YouTubevideo教程: UIScrollView – 如何在屏幕上保持你的观点

contentSize通过在UIScrollView中应用约束来隐式设置。

例如,你有一个UIScrollView里面的UIView它看起来像这样(我相信你知道):

  UIView *containerView = [[UIView alloc] init]; UIScrollView *scrollView = [[UIScrollView alloc] init]; [containerView addSubview:scrollView]; containerView.translatesAutoresizingMaskIntoConstraints = NO; scrollView.translatesAutoresizingMaskIntoConstraints = NO; NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(containerView, scrollView); [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:kNilOptions metrics:nil views:viewsDictionary]]; [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:kNilOptions metrics:nil 

这将设置scrollView来填充containerView的大小(所以containerView必须是一定的大小)。

然后你可以调整UIScrollView的contentSize,通过隐式设置它足够大来保存这样的button:

  UIButton *buttonA = [[UIButton alloc] init]; UIButton *buttonB = [[UIButton alloc] init]; UIButton *buttonC = [[UIButton alloc] init]; [scrollView addSubview:buttonA]; [scrollView addSubview:buttonB]; [scrollView addSubview:buttonC]; buttonA.translatesAutoresizingMaskIntoConstraints = NO; buttonB.translatesAutoresizingMaskIntoConstraints = NO; buttonC.translatesAutoresizingMaskIntoConstraints = NO; viewsDictionary = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC); [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|" options:kNilOptions metrics:nil views:viewsDictionary]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:viewsDictionary]]; 

关于在UIScrollView中使用AutoLayout有很多问题,我们忽略的关键是UIScrollView的内部视图对内容视图进行约束,而不是UIScrollView本身。 请参阅技术说明TN2154 ,您可以find:

UIScrollView类通过更改其边界的原点来滚动其内容。 要使用“自动布局”工作,滚动视图中的顶部,左侧,底部和右侧边缘现在意味着其内容视图的边缘。

下图将描述: 在这里输入图像描述

你可以发现尾部空间是500点,如果约束是对UIScrollView进行的,视图将被放置,并应更新其框架。 但是,没有警告,也没有错误。 因为所有的约束都是针对内容视图的。

UIScrollView将根据内部视图的约束来计算内容视图的大小。 (例如,内容尺寸:宽度= 100(前端空间)+200(视图宽度)+500(后端空间),高度= 131(顶端间隔)+200(高度)+269(底端间隔)

如何在UIScrollView中为视图添加约束:

  1. 在内容视图中对视图的位置进行映像。
  2. 将顶部,右侧,底部,左侧间距添加到内容视图的边缘,此外,还会添加这些视图的宽度和高度。

而这一切都完成了。

使用scrollview处理AutoLayout的简单方法是在滚动视图中添加包含所有子视图的容器视图。

结论:使用UIScrollView理解AutoLayout的关键是内部视图对内容视图进行约束,而不是UIScrollView本身。

附上示例代码

下面的解决scheme为我工作scrollView自动布局和没有contentSize

  1. 将n拖放到viewController并应用任何约束来覆盖所需的空间。
  2. 拖拽一个UIView在scrollView中,使其覆盖scrollView的整个空间,并将约束应用于scrollView的顶部,左侧,右侧,底部空间
  3. 根据滚动的需要设置内部视图的高度 (如果需要水平滚动,则为宽度)。 如果需要,这部分也可以从代码完成。
  4. 关键 。 在第(3)点将高度设置为某个较大的值后,回到第(2)点并确保将顶部,左侧,右侧,底部的值设置回零,因为Xcode可能在您强制更改(3)中改变了高度。

你完成了。 现在,您可以在此视图上添加任意数量的控件,并应用彼此相关的约束条件(如果没有这个视图,这些约束条件似乎无法运行)。 如果你不想使用这个视图,那么你将不得不为每个与scrollView相关的控件应用约束(不相关)。


压倒性的提示…………..

关键 。 为了清晰起见,UIScrollView是1000宽 100高。 (事实上​​,通常这些值是dynamic的,当然,这取决于设备的宽度等,但现在只要说1000宽和100高。)假设你正在做一个水平滚动。 所以把UIView里面的UIScrollView。 (即“内容视图”。)将内容视图的所有四个约束设置为滚动视图的顶部,底部,前导和尾部。 即使这看起来不对,也要把它们都设为零。 将内容UIView的高度设置为100,忘记这一点。 现在:你想水平滚动,所以设置内容视图的宽度可以说是1225。

请注意,内容视图的宽度现在比父滚动视图的宽度大225。 没关系:事实上,你必须这样做。 注意

…你设置尾部宽度为负225 …

你会认为你必须像通常那样 “匹配”宽度。 但是,如果你这样做, 那根本就行不通。

您必须将前导和尾随数字设置为零 ,从不消极(即使宽度较大)

有趣的是,实际上你可以将前导/尾随数字设置为任何正值 (试着说“50”),它给你一个反弹幅度。 (它通常看起来不错:尝试一下)任何一端的负面价值都会“默默地破坏”。

注意,令人生气的是,通常Xcode(反正是7.3.1),

会'帮助'将这些值设置为负数!

因为它试图为你自动logging。 如果是的话,它会默默地打破。 首先将所有四个值设置为零。 并且设置内容视图的宽度比示例中的“1000”宽得多。


编辑:我已经结束了使用UITableView而不是UIScrollView我的大部分要求。 由于tableView在我看来更加灵活和dynamic。

我假设你遇到了contentSize问题。 查看这篇博客文章 ,了解如何在使用“纯粹的”AutoLayout方法时处理contentSize 。 它的要点是你的约束隐含地定义了内容的大小。 在使用AutoLayout的时候你从不明确地设置它。 我在博客文章的末尾附加了示例项目,以演示其工作原理

技术笔记中有一个部分,您可能已经看过。 您可以使用固定在滚动视图边缘的约束来隐式设置滚动视图的内容大小。

这是一个简单的例子。 用一个视图创build一个具有一个滚动视图的故事板。 设置滚动视图的约束,使其适合你放置的视图的大小。

在滚动视图中添加一个视图。 使用约束显式设置该视图的大小(并确保大小大于滚动视图)。

现在,向该内部视图添加四个约束,将内部视图的四个边locking到其父滚动视图。 这四个约束将导致内容大小扩大以适应内部视图。

如果要将多个视图添加到滚动视图(例如水平布置),则应将第一个子视图的左侧locking在滚动视图的左侧,将子视图水平locking到彼此,右侧最后一个子视图的一侧到滚动视图的右侧。 这些约束将强制滚动视图的内容大小扩大,以适应所有的子视图及其约束。

如果你的问题是“如何将一堆UITextFields放在垂直滚动的UIScrollView中,当它们有焦点时,它们会移出键盘的方向”,最好的答案是:

别。

改用静态单元来使用UITableViewController。

如果您的视图控制器显示在UINavigationController中,您可以免费获得这种滚动式的行为,并且所有的内容插件都可以正常工作。

你应该像这样组织你的布局
ViewControllerView包含ScrollViewScrollView包含ContainerViewContainerView包含2个Labels
在这里输入图像描述

然后按照3个步骤让您的ScrollView可以滚动

  1. ScrollView引脚(顶部/右侧/底部/左侧)设置为ViewControllerView
    • ContainerView引脚(顶部/右侧/底部/左侧)设置为ScrollView
    • Horizontally in Container不要 Vertically in Container
    • Label1引脚( 顶部 /右侧/左侧)到ContainerView
    • Label1引脚(右/左/ 底部 )到ContainerView顶部Label1

在这里输入图像描述

这里是演示项目

希望这个帮助

纯粹的自动布局方式非常漂亮,但是如果从非自动布局迁移,则设置起来相当麻烦。 我已经做了几次,我有几个一般的秘诀:

  • 从小处着手:即使这意味着要重新创build故事板视图,只需从less数几个元素开始,慢慢构build视图,确保在添加几个元素之后testing滚动工作。
  • 关掉任何东西的转换自动化任务限制:这一直是我的约束冲突的原因。
  • 正确设置你的UIScrollView约束:确保滚动视图连接到父视图,否则它根本不会展开。

经过一段时间处理这个问题,我终于find了一个解决scheme。 我正在使用通用的课堂大小故事板(600×600)。 我创build了一个UIView(contentView)scrollView的大小,并创build了对scrollView的Top,Bottom,Leading和Trailing的约束。 然后我将contentView的大小手动剪裁到600×600。 故事板停止了尝试调整一切的大小,我可以工作,但在真实的设备或模拟器上,视图看起来很糟糕。 我做了这个剪裁大小的2个约束网点。

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint; 

然后在viewDidLoad中

 CGSize viewSize = self.view.frame.size; self.contentViewWidthConstraint.constant = viewSize.width; self.contentViewHeightConstraint.constant = viewSize.height; 

很好用。

我花了好几天的时间试图find如何使用AutoLayout查看embedded式滚动视图的解决scheme,将scrollview放置在可见屏幕中,该屏幕适用于所有设备/屏幕尺寸以及屏幕旋转。

我花了好几天的时间试着用Autolayout来做,并且靠得很近,但是从来没有接近过。 所以最后我不得不在每个屏幕上添加3行代码,在viewDidLoad中。

见下面的解决scheme

  1. 创build滚动视图,并填充任何你想要的对象
  2. 打开自动布局
  3. 然后垂直和水平居中ScrollView 中心滚动查看
  4. select视图 ,然后“添加缺less的约束” – 这是做它的事情
  5. 结果是产生了很多限制。 有两个新的视图创build:“水平空间滚动视图视图”和“垂直空间滚动视图查看”,反之亦然。
  6. 删除'Horiz space scrollview to View',让你现在在视图上留下3个约束。 2用于在视图中input滚动视图,另一个用于在滚动视图和视图之间设置垂直空间
  7. 现在通过点击和Ctrl将Vert约束链接到您的代码,并将其拖动到头文件中,并创build一个NSLayoutConstraint IBOutlet(我称为mine constraintVrtVtoSV)
  8. 现在转到.m文件,并将这些代码行添加到viewDidLoad(使用填充量来获得正确的垂直居中)

     if (IPAD) 

    {self.constraintVertVtoSV.constant = 150.0; }

  9. 这现在应该在所有设备上运行,并正确居中,并仍然正确滚动。

如果像我一样,你只需要在子视图中使用静态内容而不用担心,就像你可以这样做:

 override func viewDidLayoutSubviews() { scrollView.contentSize = CGSizeMake(320, 800) } 

类似的问题,我今天有iOS 8.4,Xcode 6.4

有一个包含滚动视图的视图,包含一个包含子视图的contentView(UIView)。

一切都是自动布局。 滚动视图边缘被固定到父视图边缘并带有约束。 内容视图边缘通过约束被固定到滚动视图边缘。

内容视图最初将拒绝作为滚动视图的全部宽度来resize。 我不得不在内容视图上添加一个额外的约束,使其宽度匹配父滚动视图。 或者我可以设置一个contentView.centerX == scrollView.centerX约束。 除了固定边缘之外,其中任何一个突然使内容视图大小合适。

 // Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0)) scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0)) 

使用窗体的视觉约束将内容视图的边固定到滚动视图,

 let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"] 

我使用例程遍历数组,并将其添加到scrollView。

我面临类似的问题。 我把每一个约束都设置好了,总是想知道为什么它仍然调整一些子视图。 我的解决scheme是将clipsToBounds设置为YES。

迅速,你可以使用这个工作解决scheme。

约束上

ScrollView :领先,尾随,顶部,底部= Superview

ContentView :前导,尾随,顶部,底部=滚动视图。 高度固定/相对于内容。

您可以将宽度约束(contentView)设置为与scrollview superview相等,但是selectremove build on time,因为您将以编程方式添加该约束。 这样IB才不会抱怨警告。

 extension UIView { func setupContentViewForViewWithScroll(contentView vwContent : UIView) { //Set constraint for scrollview content let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width) vwContent.addConstraint(constraint) self.layoutSubviews() } } 

而在视图控制器viewDidLayoutSubviews我只是调用这个方法:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() self.view.setupContentViewForViewWithScroll(contentView: vwContent) } 

我知道这是一个外行的解决scheme,而不是苹果build议在文件中,但它为我工作了两次,不同的内容,可以很快build立:在故事板视图控制器插入UIView。 在UIView插入一个表视图,dynamic,0原型单元格,风格朴素或分组。 在表格视图中插入滚动视图,在滚动视图中插入内容。 就是这样,在自定义视图控制器中没有设置。