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

Ios 如何使用Autolayout在UIScrollview上设置约束?,ios,uiscrollview,storyboard,autolayout,Ios,Uiscrollview,Storyboard,Autolayout,我花了两天时间尝试各种解决方案,以实现autolayout之前一个微不足道的scrollview设置,现在它是官方的-我一定是太愚蠢了。我主要是在故事板上设置的(嗯,就是这样) 这是我请求帮助的请求 视图树: UIView -UIView -UIView ..-UIScrollview ...-UIButton ...-UIButton ...-UIButton 按钮应该水平滚动(从左向右,反之亦然)。有人可以让我知道如何设置约束,以实现这一点,使用纯自动布局 -- 我尝试过混合方法,如下所示

我花了两天时间尝试各种解决方案,以实现autolayout之前一个微不足道的scrollview设置,现在它是官方的-我一定是太愚蠢了。我主要是在故事板上设置的(嗯,就是这样)

这是我请求帮助的请求

视图树:

UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton
按钮应该水平滚动(从左向右,反之亦然)。有人可以让我知道如何设置约束,以实现这一点,使用纯自动布局

--

我尝试过混合方法,如下所示:

UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton
…并根据苹果的技术说明为
contentview
translatesAutoResizingMacSkintoConstraints
设置固定的宽度和高度限制。按钮和滚动视图是使用约束设置的。这会使滚动视图滚动(耶),但唉,它滚动得太远了!据我所知,卷轴的宽度是我设置contentview的两倍

我也尝试了纯自动布局方法,有
contentview
也没有所有视图均为
translatesAutoresizingMaskIntoConstraints=NO
,除了
self.view
。按钮具有固定的宽度/高度约束,并固定在scrollview的所有四条边上。没有滚动条

所以我完全不明白为什么我不能让它正常工作。非常感谢您的帮助,如果您需要任何其他信息,请咨询

更新了解决方案截图- 按钮限制:

编辑@Jamie Forrest 因此,解决方案是最后一个按钮上的错误尾部约束。我设置的值不是6441,而是负数,-6441。棘手的是,在脚本中设置值时,Pin工具栏中有两个选项:

当前画布值为负值(导致无滚动),下面的选项为正值(激活滚动)。这意味着我并不愚蠢,但我想至少是半盲。不过,为了我的辩护,XCode没有显示“不正确”设置的错误,这不是有点令人不安吗

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

contentSize是通过应用UIScrollView内部的约束隐式设置的

例如,如果您在UIView中有一个UIScrollView,它将如下所示(我相信您知道):

这将设置scrollView以填充containerView的大小(因此containerView必须具有一定的大小)

然后,您可以通过隐式设置UIScrollView的contentSize,使其足够大以容纳如下按钮:

    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]];
override func viewDidLayoutSubviews() {
    scrollView.contentSize = CGSizeMake(320, 800)
}

纯自动布局方法工作得很好,但是如果您从非自动布局迁移,那么设置起来会很痛苦。我已经做过几次了,我有一些一般的建议:

  • 从小处开始:即使这意味着重新创建故事板视图,也要从几个元素开始,慢慢构建视图,确保在添加几个元素后测试滚动是否有效
  • 关闭TranslatesAutoReshizingMaskintoConstraints:对我来说,这一直是约束冲突的原因
  • 正确设置UIScrollView约束:确保滚动视图在所有方面都连接到父视图,否则它根本不会展开

我假设您遇到了
contentSize
的问题。查看使用“纯”自动布局方法时如何处理
contentSize
。其要点是,您的约束隐式地定义了内容大小。使用AutoLayout时,您从未明确设置它。我在博客文章的末尾附上了一个示例项目,以演示它是如何工作的

当您将约束粘贴到这里时,很难看到它们的确切值和设置,因此我无法确定您的屏幕截图哪里出了问题

我创建了一个与您描述的视图层次结构和约束设置非常相似的basic,而不是解释您的设置中的错误。水平滚动的工作原理与示例项目中预期的一样,该项目使用了苹果公司在中描述的“纯自动布局”方法

最初让Auto Layout使用
UIScrollView
时,我也遇到了很多麻烦。使其正常工作的关键是确保滚动视图中的所有项目加在一起都有约束,这些约束最终链接到滚动视图的所有侧面,并有助于自动布局系统确定滚动视图的内容大小,该大小将大于其框架。看起来您试图在代码中实现这一点,但可能有一些多余的约束使得contentSize太小

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


我还发现这对我理解这一切是如何运作的非常有帮助。希望所有这些都能有所帮助。

技术说明中有一段您可能已经看过了。可以使用固定到滚动视图边缘的约束隐式设置滚动视图的内容大小

这里有一个简单的例子。创建具有一个视图的情节提要,该视图具有一个滚动视图。设置滚动视图约束,使其适合放置视图的大小

在该滚动视图中添加一个
  UIView
   - ScrollView
    - Subview
    - Subview
    - Subview
    - Subview
    - ...
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint; 
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;
CGSize viewSize = self.view.frame.size;
self.contentViewWidthConstraint.constant = viewSize.width;
self.contentViewHeightConstraint.constant = viewSize.height;
override func viewDidLayoutSubviews() {
    scrollView.contentSize = CGSizeMake(320, 800)
}
if (IPAD)
// 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]|"]
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()
    }

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