AutoLayout约束以适应矩形内部的视图,保留一定的宽高比(以编程方式)

时间:2018-03-16 15:12:25

标签: ios swift autolayout snapkit

我想在一个应该具有特定宽高比的矩形内拟合图像。无论它是什么,它应该找到一个适合矩形内部的形式。我在故事板上玩了一下,得到了这个:

enter image description here

虚线边框的优先级较低(250)。 这适用于故事板。但是,我需要以编程方式创建这些约束,所以我尝试了这样做(我使用SnapKit,这只是提供了更好的AutoLayout语法。它应该是自我解释的):

let topView = UIView()
topView.translatesAutoresizingMaskIntoConstraints = false
topView.backgroundColor = .gray
view.addSubview(topView)

topView.snp.makeConstraints { (make) in
        make.top.equalToSuperview()
        make.left.equalToSuperview()
        make.trailing.equalToSuperview()
        make.height.equalTo(250)
        }

// This view should have a specific aspect ratio and fit inside topView
let holderView = UIView()
holderView.translatesAutoresizingMaskIntoConstraints = false
holderView.backgroundColor = .red
topView.addSubview(holderView)

holderView.snp.makeConstraints { (make) in
        make.center.equalToSuperview() // If I remove this one, there's no auto-layout issue, but then it's offset
        make.edges.equalToSuperview().priority(250) // sets leading, trailing, top and bottom
        make.edges.greaterThanOrEqualToSuperview().priority(1000)
        make.width.equalTo(holderView.snp.height).multipliedBy(3/2)
        }

如果将其粘贴到空的ViewController中并启动它,则会出现以下问题:

2018-03-16 15:38:50.188867+0100 DemoProject[11298:850932] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 

"<SnapKit.LayoutConstraint:0x6000000a7c80@ViewController.swift#24 UIView:0x7fcd82d12440.left == UIView:0x7fcd82d12640.left>",
"<SnapKit.LayoutConstraint:0x6000000a7ce0@ViewController.swift#25 UIView:0x7fcd82d12440.trailing == UIView:0x7fcd82d12640.trailing>",
"<SnapKit.LayoutConstraint:0x6000000a7d40@ViewController.swift#26 UIView:0x7fcd82d12440.height == 250.0>",
"<SnapKit.LayoutConstraint:0x6000000a7da0@ViewController.swift#35 UIView:0x7fcd8580dad0.centerX == UIView:0x7fcd82d12440.centerX>",
"<SnapKit.LayoutConstraint:0x6000000a7e00@ViewController.swift#35 UIView:0x7fcd8580dad0.centerY == UIView:0x7fcd82d12440.centerY>",
"<SnapKit.LayoutConstraint:0x6000000a8580@ViewController.swift#37 UIView:0x7fcd8580dad0.top >= UIView:0x7fcd82d12440.top>",
"<SnapKit.LayoutConstraint:0x6000000a8a60@ViewController.swift#37 UIView:0x7fcd8580dad0.right >= UIView:0x7fcd82d12440.right>",
"<SnapKit.LayoutConstraint:0x6000000a9360@ViewController.swift#38 UIView:0x7fcd8580dad0.width == UIView:0x7fcd8580dad0.height>",
"<NSLayoutConstraint:0x600000092cf0 'UIView-Encapsulated-Layout-Width' UIView:0x7fcd82d12640.width == 414   (active)>"


Will attempt to recover by breaking constraint <SnapKit.LayoutConstraint:0x6000000a9360@ViewController.swift#38 UIView:0x7fcd8580dad0.width == UIView:0x7fcd8580dad0.height>

当我删除居中约束make.center.equalToSuperview()时,这不会显示。但是,它错了。

故事板与我的代码有什么不同?我真的不明白这一点。我也尝试使用默认的swift语法,结果完全相同。所以我认为这不是SnapKit

的问题

有什么想法吗?谢谢你们的帮助。如果您需要更多信息,请告诉我。

编辑:我把事情搞混了。它与图像及其纵横比无关。它只是一个UIView,它应该在适合矩形内部时保持特定的宽高比。实际图像将被放入holderView。遗憾

1 个答案:

答案 0 :(得分:1)

好的 - 这是一种方式。

采取&#34;本地人&#34;您的子视图的大小,计算&#34;方面适合&#34; ratio - 即适合超视图的宽度或高度的比率,并适当地缩放另一个维度。

然后,使用centerXAnchorcenterYAnchor定位子视图,widthAnchorheightAnchor来定位子视图。

注意:如果您尝试放置图片,请根据图片尺寸计算纵横比适合尺寸,将图片放入图片视图,将图片视图比例模式设置为{ {1}},最后将约束应用于图像视图。

您应该可以按原样运行此示例。只需使用&#34; native&#34;顶部的大小值,以查看它如何使子视图适合超级视图。

fill

修改

澄清后...... 可以仅通过约束来完成。关键是&#34;优先级1000&#34; public class AspectFitViewController : UIViewController { // "native" size for the holderView let hViewWidth: CGFloat = 700.0 let hViewHeight: CGFloat = 200.0 let topView: UIView = { let v = UIView() v.translatesAutoresizingMaskIntoConstraints = false v.backgroundColor = UIColor.blue return v }() let holderView: UIView = { let v = UIView() v.translatesAutoresizingMaskIntoConstraints = false v.backgroundColor = UIColor.cyan return v }() public override func viewDidLoad() { super.viewDidLoad() view.bounds = CGRect(x: 0, y: 0, width: 400, height: 600) view.backgroundColor = .yellow // add topView view.addSubview(topView) // pin topView to leading / top / trailing topView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0).isActive = true topView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0).isActive = true topView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0).isActive = true // explicit height for topView topView.heightAnchor.constraint(equalToConstant: 250.0).isActive = true // add holderView to topView topView.addSubview(holderView) // center X and Y holderView.centerXAnchor.constraint(equalTo: topView.centerXAnchor, constant: 0.0).isActive = true holderView.centerYAnchor.constraint(equalTo: topView.centerYAnchor, constant: 0.0).isActive = true // holderView's width and height will be calculated in viewDidAppear // after topView has been laid-out by the auto-layout engine } public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let aspectWidth = topView.bounds.size.width / hViewWidth let aspectHeight = topView.bounds.size.height / hViewHeight let aspectFit = min(aspectWidth, aspectHeight) let newWidth = hViewWidth * aspectFit let newHeight = hViewHeight * aspectFit holderView.widthAnchor.constraint(equalToConstant: newWidth).isActive = true holderView.heightAnchor.constraint(equalToConstant: newHeight).isActive = true } } top约束必须为leading为零,.greaterThanOrEqualbottom约束必须为trailing为零。

.lessThanOrEqual