将完整的编程自定义视图添加到 ViewController。自动布局问题

Posted

技术标签:

【中文标题】将完整的编程自定义视图添加到 ViewController。自动布局问题【英文标题】:Adding full programamticly custom view to ViewController. AutoLayout problems 【发布时间】:2020-05-16 06:45:56 【问题描述】:

我真的不明白在创建自定义视图时如何使用布局。

主要问题在这里:

rect.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5),
rect.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1),

如果我使用乘数,它可以正常工作。但是如果我使用常量:

rect.widthAnchor.constraint(equalToConstant: self.frame.width)

它不起作用。

如何为我的自定义视图 autoLayout 约束使用任何 superView 帧大小?

class MainView: UIView 

    lazy var rect: UIView  = 
        let view = UIView()
        view.backgroundColor = .green
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    ()

    override init(frame: CGRect) 
        super.init(frame: frame)

        backgroundColor = .red
        layout()

    

    func layout() 

        addSubview(rect)

        self.translatesAutoresizingMaskIntoConstraints = false

           NSLayoutConstraint.activate([
            rect.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5),
            rect.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1),
               rect.centerYAnchor.constraint(equalTo: centerYAnchor),
               rect.centerXAnchor.constraint(equalTo: centerXAnchor)
           ])

       

    required init?(coder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    


class ViewController: UIViewController 


    let mainView = MainView(frame: .zero)

    override func loadView() 

        self.view = mainView
    

【问题讨论】:

当您创建MainView 时将其设置为.zero,如果您使用rect.widthAnchor.constraint(equalToConstant: self.frame.width),您的子视图怎么会有更好的框架? 我正在尝试在 self.view=mainView 之前设置 mainView.frame = view.frame,但它不会改变结果 【参考方案1】:

如果我使用乘数,它可以正常工作。但是如果我使用常量: rect.widthAnchor.constraint(equalToConstant: self.frame.width)

这一定会发生,在您的 viewController 中,您将 mainView 实例化为 let mainView = MainView(frame: .zero) 这将触发 initMainView,帧为零

你在init里面调用layout

override init(frame: CGRect) 
    super.init(frame: frame)

    backgroundColor = .red
    layout()


所以当MainView 框架为Zero 时,您实际上调用了布局此时如果您设置rect.widthAnchor.constraint(equalToConstant: self.frame.width),那么您实质上是在说rect.widthAnchor.constraint(equalToConstant: 0) 因此宽度设置为零

请仔细阅读声明,您将矩形宽度锚设置为 constant,在这种情况下为 0,因此即使在 UI 循环的未来阶段,您的 MainView 也会获得适当的宽度,您的矩形宽度将始终为零,因为您将其设置为常量 0 值。

但我在 self.view= mainView 之前设置了 mainView.frame = view.frame

不幸的是,对于您的 rect,此语句来晚了一点 :) 在 mainView 的 init 中调用了布局,因此 rects 宽度锚已设置为常量 0。现在尽管您更新 mainView.frame,但您的 rect 永远不会费心更新它的宽度,为什么会呢?它的约束已经解析为一个常数值,在这种情况下显然是 '0' :)

rect.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1),为什么这样有效?

在这里你说你的矩形的宽度锚等于你的MainView 的宽度锚,你不是将矩形的宽度锚设置为一个常数,而是将它设置为与 MainView 的宽度锚匹配,所以当 MainView 的框架最后设置为适当的值,您的矩形也会更新其宽度以匹配 MainViews 宽度。

坦率地说,multiplier: 1 在这种情况下毫无意义,因为如果您希望 rect 的宽度与 MainView 的宽度成比例变化(例如 50 MainView 宽度的 % 等)只有乘数才有意义

自动布局约束只不过是数学方程式,正确理解/可视化它们是获得具有约束的完美 UI 的关键

希望对你有帮助

【讨论】:

好的。现在它对我来说更容易获得。如果我理解正确,则无法使用 (equalTo: constant) ,其中常量是使用 superView 帧大小进行计算的计算属性。或者有什么方法可以通过 superView 的大小来初始化帧? 我找到的最佳解决方案是制作框架:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)【参考方案2】:

如何为我的自定义视图 autoLayout 约束使用任何 superView 帧大小?

只需删除多人游戏。

NSLayoutConstraint.activate([
        rect.heightAnchor.constraint(equalTo: heightAnchor),
        rect.widthAnchor.constraint(equalTo: widthAnchor),
        rect.centerYAnchor.constraint(equalTo: centerYAnchor),
        rect.centerXAnchor.constraint(equalTo: centerXAnchor)
        ])

【讨论】:

以上是关于将完整的编程自定义视图添加到 ViewController。自动布局问题的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式将一堆自定义视图从 XIB 添加到 UIStackView

以编程方式将 UILabel 添加到自定义 tableViewCell

以编程方式使用堆栈视图

如何以编程方式使用自动布局添加自定义视图

如何以编程方式将自定义 UIView 添加到 UIScrollView 之上的 Stackview?

以编程方式 Swift Segue