设置UIView和UIViewController之间的约束

问题描述 投票:0回答:1

我想将视图控制器添加为 UIView 内的子视图。我已经给出了所需的约束,但我不明白为什么它重叠。这是它的最少代码。我已经给出了顶部、底部、前导、尾随约束,但不确定为什么它重叠。 我想把svc放在parentView下面

     override func viewDidLoad() {
        super.viewDidLoad()
        let parentView = parentView()
        parentView.configure(movieDetails: movieDetails)

        let svc = SmiliarMovieViewController(viewModel: viewModel)
        addChild(svc)
        svc.view.translatesAutoresizingMaskIntoConstraints = false
        parentView.addSubview(svc.view)
        svc.didMove(toParent: self)

        NSLayoutConstraint.activate([
            parentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            parentView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            parentView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),

            svc.view.topAnchor.constraint(equalTo: parentView.bottomAnchor),

            svc.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            svc.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            svc.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),

        ])
    }
    
 private class parentView: UIView {
// code for parent view...

}

这是完整的代码..

final class MovieDetailsDisplayViewController: UIViewController {
    
    let movieDetails: MovieDetails
    let viewModel: MoviesDetailsViewModel

    init(movieDetails: MovieDetails, viewModel: MoviesDetailsViewModel) {
        self.movieDetails = movieDetails
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func loadView() {
        view = parentView()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let uiView = parentView()
        (view as? parentView)?.configure(movieDetails: movieDetails)
        let svc = SmiliarMovieViewController(viewModel: viewModel)
        
        view.addSubview(uiView)
        uiView.addSubview(svc.view)
        
        NSLayoutConstraint.activate([
            uiView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            uiView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            uiView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            uiView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            
            svc.view.topAnchor.constraint(equalTo: uiView.bottomAnchor),
            svc.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            svc.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            svc.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
        ])
    }
    
    private class parentView: UIView {
        
        let scrollView = UIScrollView()
        let backdropImageView = UIImageView()
        let titleLabel = UILabel()
        let overviewLabel = UILabel()
        private lazy var contentStackView = UIStackView(arrangedSubviews: [backdropImageView, titleLabel, overviewLabel])
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            commonInit()
        }
        
        private func commonInit() {
            backgroundColor = .white
            
            backdropImageView.contentMode = .scaleAspectFill
            backdropImageView.clipsToBounds = true
            
            titleLabel.font = UIFont.Heading.medium
            titleLabel.textColor = UIColor.Text.charcoal
            titleLabel.numberOfLines = 0
            titleLabel.lineBreakMode = .byWordWrapping
            titleLabel.setContentHuggingPriority(.required, for: .vertical)
            
            overviewLabel.font = UIFont.Body.small
            overviewLabel.textColor = UIColor.Text.grey
            overviewLabel.numberOfLines = 0
            overviewLabel.lineBreakMode = .byWordWrapping
            
            contentStackView.axis = .vertical
            contentStackView.spacing = 24
            contentStackView.setCustomSpacing(8, after: titleLabel)
            
            setupViewsHierarchy()
            setupConstraints()
        }
        
        private func setupViewsHierarchy() {
            addSubview(scrollView)
            scrollView.addSubview(contentStackView)
        }
        
        private func setupConstraints() {
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            backdropImageView.translatesAutoresizingMaskIntoConstraints = false
            contentStackView.translatesAutoresizingMaskIntoConstraints = false
            
            NSLayoutConstraint.activate(
                [
                    scrollView.topAnchor.constraint(equalTo: topAnchor),
                    scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
                    scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
                    scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
                    
                    backdropImageView.heightAnchor.constraint(equalTo: backdropImageView.widthAnchor, multiplier: 11 / 16, constant: 0),
                    
                    contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 24),
                    contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
                    contentStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
                    contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -24)
                ]
            )
            
            scrollView.layoutMargins = UIEdgeInsets(top: 24, left: 16, bottom: 24, right: 16)
            preservesSuperviewLayoutMargins = false
        }
        
        func configure(movieDetails: MovieDetails) {
            backdropImageView.dm_setImage(backdropPath: movieDetails.backdropPath)
            
            titleLabel.text = movieDetails.title
            
            overviewLabel.text = movieDetails.overview
        }
    }
}

这是崩溃的屏幕截图..

这是截图..

ios swift uiview uiviewcontroller addsubview
1个回答
0
投票

非常非常快速的使用子视图控制器的示例......

我们将从您的“相似”视图控制器开始。集合视图单元和创建集合视图的视图控制器:

class MySimilarCell: UICollectionViewCell {
    let imgView = UIImageView()
    let label = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        [imgView, label].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(v)
        }
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            imgView.topAnchor.constraint(equalTo: g.topAnchor),
            imgView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            imgView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            label.topAnchor.constraint(equalTo: imgView.bottomAnchor, constant: 4.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ])
        imgView.backgroundColor = .systemRed
        imgView.tintColor = .white
        label.textAlignment = .center
    }
}

class MySimilarViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
    var cv: UICollectionView!
    let data: [String] = [
        "A", "B", "C", "D", "E", "F", "G", "H"
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground
        
        let fl = UICollectionViewFlowLayout()
        fl.scrollDirection = .horizontal
        fl.itemSize = .init(width: 120.0, height: 180.0)
        cv = UICollectionView(frame: .zero, collectionViewLayout: fl)

        cv.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(cv)
        
        // so we don't have to type so much
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            cv.topAnchor.constraint(equalTo: g.topAnchor),
            cv.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            cv.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            cv.heightAnchor.constraint(equalToConstant: 180.0),
        ])
        
        cv.dataSource = self
        cv.delegate = self
        cv.register(MySimilarCell.self, forCellWithReuseIdentifier: "c")
        
        // so we can see the collection view framing
        cv.backgroundColor = .cyan
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let c = collectionView.dequeueReusableCell(withReuseIdentifier: "c", for: indexPath) as! MySimilarCell
        if let img = UIImage(systemName: "\(data[indexPath.item].lowercased()).circle") {
            c.imgView.image = img
        }
        c.label.text = data[indexPath.item]
        return c
    }
}

如果您将

MySimilarViewController
设置为初始视图控制器并运行应用程序,它应该如下所示:

接下来,我们将在垂直堆栈视图中、滚动视图中设置“父”控制器,其中包含图像视图、标题标签和段落标签,底部留有“子”控制器的空间:

class MyMainViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBackground

        // add an image view, title label, paragraph label
        //  to a vertical stack view
        //      added to a scroll view
        
        let imgView = UIImageView()
        imgView.backgroundColor = .white
        imgView.tintColor = .systemOrange
        if let img = UIImage(systemName: "swift") {
            imgView.image = img
        }
        
        let titleLabel = UILabel()
        titleLabel.backgroundColor = .green
        titleLabel.font = .systemFont(ofSize: 28.0, weight: .bold)
        titleLabel.text = "Spirited Away"
        
        let paraLabel = UILabel()
        paraLabel.backgroundColor = .green
        paraLabel.font = .systemFont(ofSize: 20.0, weight: .regular)
        paraLabel.numberOfLines = 0
        paraLabel.text = "A young girl, Chihiro, becomes trapped in a strange new world of spirits. When her parents undergo a mysterious transformation, she must call upon the courage she never knew she had to free her family."

        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.spacing = 20.0

        stackView.addArrangedSubview(imgView)
        stackView.addArrangedSubview(titleLabel)
        stackView.addArrangedSubview(paraLabel)

        let scrollView = UIScrollView()
        
        // so we can see the scroll view's framing
        scrollView.backgroundColor = .systemYellow
        
        stackView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(stackView)

        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)

        let addHereView = UIView()
        addHereView.backgroundColor = .systemBlue
        
        addHereView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(addHereView)
        
        // so we don't have to type so much
        let g = view.safeAreaLayoutGuide
        let cg = scrollView.contentLayoutGuide
        let fg = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            scrollView.bottomAnchor.constraint(equalTo: addHereView.topAnchor, constant: -20.0),
            
            stackView.topAnchor.constraint(equalTo: cg.topAnchor, constant: 20.0),
            stackView.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20.0),
            stackView.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20.0),
            stackView.bottomAnchor.constraint(equalTo: cg.bottomAnchor, constant: -20.0),

            stackView.widthAnchor.constraint(equalTo: fg.widthAnchor, constant: -40.0),
            
            // image view needs height
            imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor, multiplier: 1.0),
            
            addHereView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            addHereView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            addHereView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
            
            // height of the child content
            addHereView.heightAnchor.constraint(equalToConstant: 180.0),

        ])
        
    }
    
}

现在,如果我们将

MyMainViewController
设置为初始视图控制器,我们应该得到:

图像和标签位于(黄色)滚动视图中,我们有一个蓝色视图,我们将在其中添加子控制器的视图。

因此,在

viewDidLoad()
中的
MyMainViewController
末尾,我们将添加以下内容:

    let similarVC = MySimilarViewController()
    addChild(similarVC)
    
    // safely unwrap MySimilarViewController's view
    guard let similarView = similarVC.view else {
        // this should never happen, unless we've really mis-written the detail view controller
        fatalError("Similar VC had no view!!!")
    }
    
    similarView.translatesAutoresizingMaskIntoConstraints = false
    addHereView.addSubview(similarView)
    
    NSLayoutConstraint.activate([
        similarView.topAnchor.constraint(equalTo: addHereView.topAnchor, constant: 0.0),
        similarView.leadingAnchor.constraint(equalTo: addHereView.leadingAnchor, constant: 0.0),
        similarView.trailingAnchor.constraint(equalTo: addHereView.trailingAnchor, constant: 0.0),
        similarView.bottomAnchor.constraint(equalTo: addHereView.bottomAnchor, constant: 0.0),
    ])
    
    similarVC.didMove(toParent: self)

因此,我们添加了

MySimilarViewController
的实例作为子视图控制器,并将其
view
添加为蓝色视图的子视图。

我们得到这个:

© www.soinside.com 2019 - 2024. All rights reserved.