使用 UIScrollView 和 AutoLayout 以编程方式创建控制器无法正确调整视图大小

Posted

技术标签:

【中文标题】使用 UIScrollView 和 AutoLayout 以编程方式创建控制器无法正确调整视图大小【英文标题】:Programmatically creating controller with UIScrollView and AutoLayout is not sizing the views properly 【发布时间】:2015-01-21 00:23:43 【问题描述】:

我正在尝试以编程方式创建一个视图控制器,它将以可滚动的方式布置子视图。我正在尝试将 AutoLayout 与 UIScrollView 一起使用,并已阅读这方面的所有技术说明和 SO 答案。但我无法做到这一点 - 似乎我在这里缺少的创建/使用或 UIScrollView 有一些细微差别。

我的代码在下面,我看到的输出也显示在下面的图片中。

我的期望是我会看到占据整个屏幕的棕色和绿色条纹(子视图)。我知道我必须指定子视图的高度,但我不明白为什么水平尺寸不起作用。如果我没有指定水平尺寸,我希望我的子视图会被拉伸并占据屏幕的宽度,但事实并非如此。

这是我的控制器的代码。

class ScrollableRowHeadersViewController : UIViewController 

var scrollView : UIScrollView!

override func loadView() 
    self.view = UIView(frame: CGRectZero)
    scrollView = UIScrollView()
    scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
    self.view.addSubview(scrollView)
    scrollView.backgroundColor = UIColor.blueColor()
    self.view.addVisualConstraint("H:|-0-[scrollView]-0-|", viewsDict: ["scrollView" : scrollView])
    self.view.addVisualConstraint("V:|-0-[scrollView]-0-|", viewsDict: ["scrollView" : scrollView])
    self.view.contentMode = UIViewContentMode.Redraw


//load all the subviews after the main view and scrollview loaded.
override func viewDidLoad() 
    var viewsDict = [String: UIView]()
    var vertical_constraints = "V:|"
    scrollView.autoresizesSubviews = true

    for i in 1...100 
        var subview = UIView()
        subview.setTranslatesAutoresizingMaskIntoConstraints(false)
        subview.backgroundColor = (i%2 == 0 ? UIColor.brownColor() : UIColor.greenColor())
        viewsDict["subview_\(i)"] = subview
        self.scrollView.addSubview(subview)
        vertical_constraints += "[subview_\(i)(==50)]"
        self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[subview_\(i)]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
    

    vertical_constraints += "|"
    self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(vertical_constraints, options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))

这是水平约束设置为 H:|[subview_(i)]|

的输出

这是水平约束设置为 H:|[subview_(i)(==100)]|

的输出

在任何一种情况下,我都希望在整个屏幕宽度上看到交替出现的棕色和绿色条纹。

我错过了什么?提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

经过更多的痛苦和仔细阅读,这种行为的原因和答案变得更加清晰。在this SO question 也有很好的描述。我希望技术说明更英文,但@rdelmar 和@Rob 非常清楚地解释了“contentView 上的约束用于设置 scrollView 的 contentSize”。

这是修改后的代码和结果(我认为这是正确的解决方案)。我的视图层次结构现在是这样的: ViewController -> UIView (mainView) -> UIScrollVIew -> UIView (contentView) -> UIViews (subviews)

contentView 和 mainView 之间有额外的宽度限制。另外,所有的subview都添加到contentView中,而不是直接添加到scrollView中。

class ScrollableRowHeadersViewController : UIViewController 

var scrollView : UIScrollView!
var contentView : UIView!

override func loadView() 
    super.loadView()
    self.view = UIView(frame: CGRectZero)
    scrollView = UIScrollView(frame:CGRectZero)
    scrollView.sizeToFit()
    scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
    self.view.addSubview(scrollView)
    scrollView.backgroundColor = UIColor.blueColor()

    contentView = UIView()
    contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
    contentView.backgroundColor = UIColor.redColor()
    scrollView.addSubview(contentView)

    self.view.addVisualConstraint("H:|-0-[scrollView]-0-|", viewsDict: ["scrollView" : scrollView])
    self.view.addVisualConstraint("V:|-0-[scrollView]-0-|", viewsDict: ["scrollView" : scrollView])

    self.view.addVisualConstraint("H:|[contentView]|", viewsDict: ["contentView" : contentView])
    self.view.addVisualConstraint("V:|[contentView]|", viewsDict: ["contentView" : contentView])

    //make the width of content view to be the same as that of the containing view.
    self.view.addVisualConstraint("H:[contentView(==mainView)]", viewsDict: ["contentView" : contentView, "mainView" : self.view])

    self.view.contentMode = UIViewContentMode.Redraw


//load all the subviews after the main view and scrollview loaded.
override func viewDidLoad() 
    var viewsDict = [String: UIView]()
    viewsDict["contentView"] = contentView
    viewsDict["super"] = self.view
    var vertical_constraints = "V:|"

    for i in 1...50 
        var subview = UIView()
        subview.setTranslatesAutoresizingMaskIntoConstraints(false)
        subview.backgroundColor = (i%2 == 0 ? UIColor.brownColor() : UIColor.greenColor())
        viewsDict["subview_\(i)"] = subview
        contentView.addSubview(subview)

        vertical_constraints += "[subview_\(i)(==50)]"
        self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[subview_\(i)]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
    

    vertical_constraints += "|"
    self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(vertical_constraints, options: NSLayoutFormatOptions.AlignAllLeft, metrics: nil, views: viewsDict))

这是我期望的输出:

【讨论】:

我还发现***.com/questions/16843633/… 对解决这个问题非常有用。【参考方案2】:

对于滚动视图,“|”指的是 contentView,而不是滚动视图,因此通过将 subview 设置为 100,您告诉 contentView 的宽度为 100 磅(同样在您的第一种情况下,因为您没有设置宽度,所以您得到一个 0 宽度的 contentView)。你应该这样做,

self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[subview_\(i)(==width)]|", options: NSLayoutFormatOptions(0), metrics:["width": self.scrollView.frame.size.width], views: viewsDict))

【讨论】:

以上是关于使用 UIScrollView 和 AutoLayout 以编程方式创建控制器无法正确调整视图大小的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIScrollView 和自动布局的图像滑块

使用 UIScrollView 和 NSNotificationCenter 继续上课

UIScrollView和UIPageControl的使用(实现图片的循环滚动)

使用 UIScrollView 进行放大和缩小视图

如何同时使用 UIScrollView 和 UITableView 实现平滑滚动?

使用UIScrollView和UIPageControl做一个能够用手势来切换图片的效果