【问题标题】:Set NSLayoutConstraint of view to top right将视图的 NSLayoutConstraint 设置为右上角
【发布时间】:2015-08-22 02:24:08
【问题描述】:

我在想办法解决这个问题时束手无策。在 CSS 中,你可以这样做:

img {
  position: absolute;
  width: 50px;
  height: 50px;
  top: 0;
  right: 0;
}

在 Swift 中,我使用编程接口来设置图像的布局约束。它看起来像这样:

let img = UIImageView(image: UIImage(named: "my-image"))
img.setTranslatesAutoresizingMaskIntoConstraints(false)
mainScrollView.addSubview(img)
mainScrollView.addConstraint(NSLayoutConstraint(item: img, attribute: .Width,    relatedBy: .Equal, toItem: nil,            attribute: .NotAnAttribute, multiplier: 1, constant: 50))
mainScrollView.addConstraint(NSLayoutConstraint(item: img, attribute: .Height,   relatedBy: .Equal, toItem: nil,            attribute: .NotAnAttribute, multiplier: 1, constant: 50))
mainScrollView.addConstraint(NSLayoutConstraint(item: img, attribute: .Top,      relatedBy: .Equal, toItem: mainScrollView, attribute: .Top,            multiplier: 1, constant: 0))
mainScrollView.addConstraint(NSLayoutConstraint(item: img, attribute: .Trailing, relatedBy: .Equal, toItem: mainScrollView, attribute: .Trailing,       multiplier: 1, constant: 0))

但是由于某些奇怪的原因,它尊重宽度和高度布局约束,甚至是顶部约束。但它基本上在屏幕左侧 50 处。如果我将最后一个 .Trailing 常量设置为 50,它实际上会将它移到左上角的视图中(是的,我对此很困惑)。

【问题讨论】:

    标签: ios swift uiscrollview autolayout


    【解决方案1】:

    约束应应用于与约束中涉及的视图最近的共同祖先的视图。所以我可以在您发布的代码中看到两个错误:

    1. 如果您正在设置视图的heightwidth,则视图本身是最近的公共祖先视图,因此应将约束直接应用于它。所以你的代码应该是:

      item.addConstraint(NSLayoutConstraint(item: img, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50))
      item.addConstraint(NSLayoutConstraint(item: img, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 50))
      
    2. 由于这个约束中涉及的视图:

      NSLayoutConstraint(item: img, attribute: .Top, relatedBy: .Equal, toItem: mainView, attribute: .Top, multiplier: 1, constant: 0))
      

      一个是另一个的子视图,它应该应用于父视图:

      mainView.addConstraint(NSLayoutConstraint(item: img, attribute: .Top, relatedBy: .Equal, toItem: mainView, attribute: .Top, multiplier: 1, constant: 0)))
      

    关于Trailing 属性的问题,您应该考虑在添加约束时定义此公式:

    item1.attribute = item2.attribute + constant
    

    因此,如果您要定义两个属性均为 Trailing 的约束,您应该使用负常量来让一个视图包含在另一个视图中:

    --------------------------
    View1                    |
    -------------            |
    View2       |  - (-50) - |  
    

    【讨论】:

    • 感谢您的解释!这个公式确实使它更加清晰。
    【解决方案2】:

    您是否尝试过不涉及代码的方式?使用故事板视图右下角的按钮?

    【讨论】:

    • 我熟悉界面构建器选项。但是,这是我以编程方式构建了许多视图的情况,因此我还需要在代码中设置它们的位置。
    【解决方案3】:

    您只想将其设置在右上角,宽度和高度均为 50?也许你可以这样做:

    let img = UIImageView(image: UIImage(named: "my-image"))
    img.setTranslatesAutoresizingMaskIntoConstraints(false)
    mainScrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[img(50)]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["img" : img]))
    mainScrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[img(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: ["img" : img]))
    

    【讨论】:

    • 奇怪。那里也没有骰子。
    • 你测试过[mainView]在正确的位置吗?
    • 问题中有一个错字——他们都是mainScrollView。尽管如此,所有约束都在img 上设置。无论如何,mainScrollView 上的约束设置为顶部、前导、尾随和底部的全部 0(零)——因此它占据了整个视图。
    • 对于我的测试,似乎是 mainView 导致了这个错误,如果我设置 mainView 的框架没有约束,它工作得很好。我现在不知道为什么
    • 这太奇怪了。想知道是什么导致它这样做。
    【解决方案4】:

    问题在于,与标准视图不同,滚动视图与其子视图之间的约束并不决定子视图的大小,而是滚动视图的contentSize很好奇,但这实际上是一个很棒的功能,让我们摆脱了手动计算contentSize 的工作。如需更多信息,请参阅Technical Note TN2154

    但这意味着,为了指定滚动视图中子视图的大小,您实际上必须引用滚动视图外部的内容(例如,视图控制器的主要view)。

    因此,您可以在滚动视图中放置一个“容器”视图,并将图像视图放在其右上角。然后您可以将容器定义为主视图的宽度。这样你就可以实现两个目标,指定滚动视图内容的宽度,并指定图像视图在其中的位置:

    // define the container inside the scroll view
    
    let containerView = UIView()
    containerView.setTranslatesAutoresizingMaskIntoConstraints(false)
    scrollView.addSubview(containerView)
    
    // put the imageView in the container
    
    let imageView = UIImageView(image: UIImage(named: "my-image"))
    imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
    containerView.addSubview(imageView)
    
    let views = ["containerView" : containerView, "view" : view, "imageView" : imageView]
    
    // constraints for the container
    
    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[containerView(==view)]|", options: nil, metrics: nil, views: views))
    scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[containerView]|", options: nil, metrics: nil, views: views))
    
    // define the imageview constraints
    
    containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[imageView(==50)]|", options: nil, metrics: nil, views: views))
    containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[imageView(==50)]", options: nil, metrics: nil, views: views))
    

    【讨论】:

    • 很抱歉,主要问题中有一个错字。只有主要的view,然后是mainScrollView。我不小心输入了不存在的mainView。因此:view > mainScrollView > img
    • @ded - 大声笑。这很有趣,因为在滚动视图和图像视图之间有一个视图是您实际解决此问题的方法。我已经修改了我的答案以使其更清楚。我的回答的要点仍然存在,您需要在其中说明滚动视图的内容等于主视图的宽度。您可能已经定义了指定滚动视图的frame 的约束,但您也需要指定contentSize 的宽度。
    猜你喜欢
    • 2013-08-08
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-01
    • 1970-01-01
    相关资源
    最近更新 更多