首页 > 解决方案 > Swift - 自动布局约束 UIView-Encapsulated-Layout-Width

问题描述

我正在尝试以编程方式执行 UI,但遇到了奇怪的约束错误,但是当我运行应用程序时,它看起来符合预期。

在此处输入图像描述

我正在尝试做的事情:

我有一个 ViewControllerTodayVC我有一个UIView并且我正在尝试MWStepsActivityVC在该视图中呈现内容。

这是我的 TodayVC:

class TodayVC: UIViewController {
    
    let scrollView = UIScrollView()
    let contentView = UIView()
    
    let stepsActivityView = UIView()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureViewController()
        configureScrollView()
        configureContainerViews()
        layoutUI()
    }
    
    func configureViewController() {
        view.backgroundColor = .systemBackground
    }
    
    func configureScrollView() {
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)
        scrollView.pinToEdges(of: view)
        contentView.pinToEdges(of: scrollView)
        
        NSLayoutConstraint.activate([
            contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
            contentView.heightAnchor.constraint(equalToConstant: 600)
        ])
    }
    
    func configureContainerViews() {
        self.add(childVC: MWStepsActivityVC(activityType: .steps), to: self.stepsActivityView)
    }
    
    func layoutUI() {
        contentView.addSubview(stepsActivityView)
        stepsActivityView.translatesAutoresizingMaskIntoConstraints = false
        
        let padding: CGFloat = 20
        let itemHeight: CGFloat = 140
        
        NSLayoutConstraint.activate([
            stepsActivityView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: padding),
            stepsActivityView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -padding),
            stepsActivityView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: padding),
            stepsActivityView.heightAnchor.constraint(equalToConstant: itemHeight),
        ])
        
        print("TodayVC view width \(view.frame.size.width)")
    }
    
    func add(childVC: UIViewController, to containerView: UIView) {
        addChild(childVC)
        containerView.addSubview(childVC.view)
        childVC.view.frame = containerView.bounds
        childVC.didMove(toParent: self)
    }
}

UIView 扩展:

extension UIView {
    func addSubviews(_ views: UIView...) {
        for view in views {
            addSubview(view)
        }
    }
    
    func pinToEdges(of superview: UIView) {
        translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            topAnchor.constraint(equalTo: superview.topAnchor),
            leadingAnchor.constraint(equalTo: superview.leadingAnchor),
            trailingAnchor.constraint(equalTo: superview.trailingAnchor),
            bottomAnchor.constraint(equalTo: superview.bottomAnchor),
        ])
    }
}

MWStepsActivityVC:

class MWActivityVC: UIViewController {
    
    let iconImageView = UIImageView()
    let titleLabel = UILabel()
    let counterLabel = UILabel()
    
    init(activityType: ActivityType) {
        super.init(nibName: nil, bundle: nil)
        self.set(activityType: activityType)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureBackgroundView()
        layoutUI()
        placeholderData()
    }
    
    fileprivate func placeholderData() {
        iconImageView.image = SFSymbols.steps
        titleLabel.text = "StepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsStepsSteps"
        counterLabel.text = "9000"
        counterLabel.backgroundColor = .red
    }
    
    fileprivate func configureBackgroundView() {
        view.layer.cornerRadius = 18
    }

    
    fileprivate func layoutUI() {
        view.addSubviews(iconImageView, titleLabel, counterLabel)
        iconImageView.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        counterLabel.translatesAutoresizingMaskIntoConstraints = false
        
        let padding: CGFloat = 20
        NSLayoutConstraint.activate([
            iconImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: padding),
            iconImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
            iconImageView.heightAnchor.constraint(equalToConstant: 20),
            iconImageView.widthAnchor.constraint(equalToConstant: 20),
            
            titleLabel.centerYAnchor.constraint(equalTo: iconImageView.centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: padding),
            titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
            titleLabel.heightAnchor.constraint(equalToConstant: 20),
            
            counterLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -padding),
            counterLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
            counterLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
            counterLabel.heightAnchor.constraint(equalToConstant: 40)
        ])
        
        print("MWStepsActivityVC view width \(view.frame.size.width)")
    }
}

我收到这些错误:

"<NSLayoutConstraint:0x600002228320 H:|-(20)-[UIImageView:0x7fc0abe077a0]   (active, names: '|':UIView:0x7fc0abd10850 )>",
"<NSLayoutConstraint:0x6000022283c0 UIImageView:0x7fc0abe077a0.width == 20   (active)>",
"<NSLayoutConstraint:0x600002228460 H:[UIImageView:0x7fc0abe077a0]-(20)-[UILabel:0x7fc0abe08a70]   (active)>",
"<NSLayoutConstraint:0x6000022284b0 UILabel:0x7fc0abe08a70.trailing == UIView:0x7fc0abd10850.trailing - 20   (active)>",
"<NSLayoutConstraint:0x600002230b90 'UIView-Encapsulated-Layout-Width' UIView:0x7fc0abd10850.width == 0   (active)>",

"<NSLayoutConstraint:0x600002228320 H:|-(20)-[UIImageView:0x7fc0abe077a0]   (active, names: '|':UIView:0x7fc0abd10850 )>",
"<NSLayoutConstraint:0x600002228460 H:[UIImageView:0x7fc0abe077a0]-(20)-[UILabel:0x7fc0abe08a70]   (active)>",
"<NSLayoutConstraint:0x6000022284b0 UILabel:0x7fc0abe08a70.trailing == UIView:0x7fc0abd10850.trailing - 20   (active)>",
"<NSLayoutConstraint:0x600002230b90 'UIView-Encapsulated-Layout-Width' UIView:0x7fc0abd10850.width == 0   (active)>",


"<NSLayoutConstraint:0x6000022285a0 H:|-(20)-[UILabel:0x7fc0abe08ce0]   (active, names: '|':UIView:0x7fc0abd10850 )>",
"<NSLayoutConstraint:0x6000022285f0 UILabel:0x7fc0abe08ce0.trailing == UIView:0x7fc0abd10850.trailing - 20   (active)>",
"<NSLayoutConstraint:0x600002230b90 'UIView-Encapsulated-Layout-Width' UIView:0x7fc0abd10850.width == 0   (active)>"

我尝试使用wtfautolayout.com网站来了解问题所在,似乎问题在于UIView-Encapsulated-Layout-Width它认为它设置为 0,但是当我尝试打印时,view.frame.size.width我得到了正确的宽度:

MWStepsActivityVC view width 375.0
TodayVC view width 375.0 

有人可以帮我吗?我已经为此苦苦挣扎了一天。

标签: iosswiftautolayoutconstraintsnslayoutconstraint

解决方案


最后我能够修复它。我忘了configureContainerViews在主线程上运行...

DispatchQueue.main.async {
    self.configureContainerViews()
}

推荐阅读